168349Sobrien/*- 268349Sobrien * Copyright (c) 2010-2011, Aleksandr Rybalko <ray@ddteam.net> 3226048Sobrien * Copyright (c) 2009, Oleksandr Tymoshenko <gonzo@FreeBSD.org> 468349Sobrien * Copyright (c) 2009, Luiz Otavio O Souza. 568349Sobrien * All rights reserved. 668349Sobrien * 768349Sobrien * Redistribution and use in source and binary forms, with or without 868349Sobrien * modification, are permitted provided that the following conditions 968349Sobrien * are met: 1068349Sobrien * 1. Redistributions of source code must retain the above copyright 1168349Sobrien * notice unmodified, this list of conditions, and the following 1268349Sobrien * disclaimer. 1368349Sobrien * 2. Redistributions in binary form must reproduce the above copyright 1468349Sobrien * notice, this list of conditions and the following disclaimer in the 1568349Sobrien * documentation and/or other materials provided with the distribution. 1668349Sobrien * 1768349Sobrien * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 1868349Sobrien * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1968349Sobrien * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 2068349Sobrien * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 2168349Sobrien * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 2268349Sobrien * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 23226048Sobrien * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 24226048Sobrien * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 25226048Sobrien * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 26226048Sobrien * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27226048Sobrien * SUCH DAMAGE. 28226048Sobrien */ 29226048Sobrien 30226048Sobrien/* 31226048Sobrien * GPIO driver for RT305X SoC. 32226048Sobrien */ 33226048Sobrien 34133359Sobrien#include <sys/cdefs.h> 35133359Sobrien__FBSDID("$FreeBSD$"); 36133359Sobrien 37133359Sobrien#include <sys/param.h> 38133359Sobrien#include <sys/systm.h> 39186690Sobrien#include <sys/bus.h> 40133359Sobrien 41133359Sobrien#include <sys/kernel.h> 42133359Sobrien#include <sys/module.h> 43133359Sobrien#include <sys/rman.h> 44186690Sobrien#include <sys/lock.h> 45133359Sobrien#include <sys/mutex.h> 46186690Sobrien#include <sys/gpio.h> 47133359Sobrien 48133359Sobrien#include <machine/bus.h> 49133359Sobrien#include <machine/resource.h> 50186690Sobrien#include <mips/rt305x/rt305xreg.h> 51186690Sobrien#include <mips/rt305x/rt305x_gpio.h> 52186690Sobrien#include <mips/rt305x/rt305x_gpiovar.h> 53186690Sobrien#include <mips/rt305x/rt305x_sysctlvar.h> 54186690Sobrien 55#include "gpio_if.h" 56 57#ifdef notyet 58#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \ 59 GPIO_PIN_INVOUT | GPIO_PIN_REPORT ) 60#else 61#define DEFAULT_CAPS (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT | GPIO_PIN_INVIN | \ 62 GPIO_PIN_INVOUT ) 63#endif 64 65/* 66 * Helpers 67 */ 68static void rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, 69 struct gpio_pin *pin, uint32_t flags); 70 71/* 72 * Driver stuff 73 */ 74static int rt305x_gpio_probe(device_t dev); 75static int rt305x_gpio_attach(device_t dev); 76static int rt305x_gpio_detach(device_t dev); 77static int rt305x_gpio_intr(void *arg); 78 79int rt305x_get_int_mask (device_t); 80void rt305x_set_int_mask (device_t, uint32_t); 81int rt305x_get_int_status(device_t); 82void rt305x_set_int_status(device_t, uint32_t); 83 84/* 85 * GPIO interface 86 */ 87static int rt305x_gpio_pin_max(device_t dev, int *maxpin); 88static int rt305x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps); 89static int rt305x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t 90 *flags); 91static int rt305x_gpio_pin_getname(device_t dev, uint32_t pin, char *name); 92static int rt305x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags); 93static int rt305x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value); 94static int rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val); 95static int rt305x_gpio_pin_toggle(device_t dev, uint32_t pin); 96 97static void 98rt305x_gpio_pin_configure(struct rt305x_gpio_softc *sc, struct gpio_pin *pin, 99 unsigned int flags) 100{ 101 GPIO_LOCK(sc); 102 103 /* 104 * Manage input/output 105 */ 106 if (flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) { 107 pin->gp_flags &= ~(GPIO_PIN_INPUT|GPIO_PIN_OUTPUT); 108 if (flags & GPIO_PIN_OUTPUT) { 109 pin->gp_flags |= GPIO_PIN_OUTPUT; 110 GPIO_BIT_SET(sc, pin->gp_pin, DIR); 111 } 112 else { 113 pin->gp_flags |= GPIO_PIN_INPUT; 114 GPIO_BIT_CLR(sc, pin->gp_pin, DIR); 115 } 116 } 117 118 if (flags & GPIO_PIN_INVOUT) { 119 pin->gp_flags |= GPIO_PIN_INVOUT; 120 GPIO_BIT_SET(sc, pin->gp_pin, POL); 121 } 122 else { 123 pin->gp_flags &= ~GPIO_PIN_INVOUT; 124 GPIO_BIT_CLR(sc, pin->gp_pin, POL); 125 } 126 127 if (flags & GPIO_PIN_INVIN) { 128 pin->gp_flags |= GPIO_PIN_INVIN; 129 GPIO_BIT_SET(sc, pin->gp_pin, POL); 130 } 131 else { 132 pin->gp_flags &= ~GPIO_PIN_INVIN; 133 GPIO_BIT_CLR(sc, pin->gp_pin, POL); 134 } 135 136#ifdef notyet 137 /* Enable interrupt bits for rising/falling transitions */ 138 if (flags & GPIO_PIN_REPORT) { 139 pin->gp_flags |= GPIO_PIN_REPORT; 140 GPIO_BIT_SET(sc, pin->gp_pin, RENA); 141 GPIO_BIT_SET(sc, pin->gp_pin, FENA); 142 device_printf(sc->dev, "Will report interrupt on pin %d\n", 143 pin->gp_pin); 144 145 } 146 else { 147 pin->gp_flags &= ~GPIO_PIN_REPORT; 148 GPIO_BIT_CLR(sc, pin->gp_pin, RENA); 149 GPIO_BIT_CLR(sc, pin->gp_pin, FENA); 150 } 151#else 152 /* Disable generating interrupts for now */ 153 GPIO_BIT_CLR(sc, pin->gp_pin, RENA); 154 GPIO_BIT_CLR(sc, pin->gp_pin, FENA); 155#endif 156 157 GPIO_UNLOCK(sc); 158} 159 160static int 161rt305x_gpio_pin_max(device_t dev, int *maxpin) 162{ 163 164 *maxpin = NGPIO - 1; 165 return (0); 166} 167 168static int 169rt305x_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) 170{ 171 struct rt305x_gpio_softc *sc = device_get_softc(dev); 172 int i; 173 174 for (i = 0; i < sc->gpio_npins; i++) { 175 if (sc->gpio_pins[i].gp_pin == pin) 176 break; 177 } 178 179 if (i >= sc->gpio_npins) 180 return (EINVAL); 181 182 GPIO_LOCK(sc); 183 *caps = sc->gpio_pins[i].gp_caps; 184 GPIO_UNLOCK(sc); 185 186 return (0); 187} 188 189static int 190rt305x_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) 191{ 192 struct rt305x_gpio_softc *sc = device_get_softc(dev); 193 int i; 194 195 for (i = 0; i < sc->gpio_npins; i++) { 196 if (sc->gpio_pins[i].gp_pin == pin) 197 break; 198 } 199 200 if (i >= sc->gpio_npins) 201 return (EINVAL); 202 203 GPIO_LOCK(sc); 204 *flags = sc->gpio_pins[i].gp_flags; 205 GPIO_UNLOCK(sc); 206 207 return (0); 208} 209 210static int 211rt305x_gpio_pin_getname(device_t dev, uint32_t pin, char *name) 212{ 213 struct rt305x_gpio_softc *sc = device_get_softc(dev); 214 int i; 215 216 for (i = 0; i < sc->gpio_npins; i++) { 217 if (sc->gpio_pins[i].gp_pin == pin) 218 break; 219 } 220 221 if (i >= sc->gpio_npins) 222 return (EINVAL); 223 224 GPIO_LOCK(sc); 225 memcpy(name, sc->gpio_pins[i].gp_name, GPIOMAXNAME); 226 GPIO_UNLOCK(sc); 227 228 return (0); 229} 230 231static int 232rt305x_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) 233{ 234 int i; 235 struct rt305x_gpio_softc *sc = device_get_softc(dev); 236 237 for (i = 0; i < sc->gpio_npins; i++) { 238 if (sc->gpio_pins[i].gp_pin == pin) 239 break; 240 } 241 242 if (i >= sc->gpio_npins) 243 return (EINVAL); 244 245 /* Check for unwanted flags. */ 246 if ((flags & sc->gpio_pins[i].gp_caps) != flags) 247 return (EINVAL); 248 249 /* Can't mix input/output together */ 250 if ((flags & (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) == 251 (GPIO_PIN_INPUT|GPIO_PIN_OUTPUT)) 252 return (EINVAL); 253 254 rt305x_gpio_pin_configure(sc, &sc->gpio_pins[i], flags); 255 256 257 return (0); 258} 259 260static int 261rt305x_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) 262{ 263 struct rt305x_gpio_softc *sc = device_get_softc(dev); 264 int i; 265 266 for (i = 0; i < sc->gpio_npins; i++) { 267 if (sc->gpio_pins[i].gp_pin == pin) 268 break; 269 } 270 271 if (i >= sc->gpio_npins) 272 return (EINVAL); 273 274 275 GPIO_LOCK(sc); 276 if (value) GPIO_BIT_SET(sc, i, DATA); 277 else GPIO_BIT_CLR(sc, i, DATA); 278 GPIO_UNLOCK(sc); 279 280 return (0); 281} 282 283static int 284rt305x_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) 285{ 286 struct rt305x_gpio_softc *sc = device_get_softc(dev); 287 int i; 288 289 for (i = 0; i < sc->gpio_npins; i++) { 290 if (sc->gpio_pins[i].gp_pin == pin) 291 break; 292 } 293 294 if (i >= sc->gpio_npins) 295 return (EINVAL); 296 297 GPIO_LOCK(sc); 298 *val = GPIO_BIT_GET(sc, i, DATA); 299 GPIO_UNLOCK(sc); 300 301 return (0); 302} 303 304static int 305rt305x_gpio_pin_toggle(device_t dev, uint32_t pin) 306{ 307 int i; 308 struct rt305x_gpio_softc *sc = device_get_softc(dev); 309 310 for (i = 0; i < sc->gpio_npins; i++) { 311 if (sc->gpio_pins[i].gp_pin == pin) 312 break; 313 } 314 315 if (i >= sc->gpio_npins) 316 return (EINVAL); 317 318 GPIO_LOCK(sc); 319 GPIO_BIT_SET(sc, i, TOG); 320 GPIO_UNLOCK(sc); 321 322 return (0); 323} 324 325static int 326rt305x_gpio_intr(void *arg) 327{ 328 struct rt305x_gpio_softc *sc = arg; 329#ifdef notyet 330 uint32_t i; 331#endif 332 uint64_t input, value; 333#ifdef notyet 334 uint64_t reset_pin; 335 char notify[16]; 336 char pinname[6]; 337#endif 338 339 /* Read all reported pins */ 340 input = GPIO_READ_ALL(sc, INT); 341 /* Clear int status */ 342 GPIO_WRITE_ALL(sc, INT, input); 343 /* Clear report for OUTs */ 344 input &= ~GPIO_READ_ALL(sc, DIR); 345 value = input & GPIO_READ_ALL(sc, DATA); 346 347 if (!input) goto intr_done; 348 349#ifdef notyet 350 /* if reset_gpio and this pin is input */ 351 if (sc->reset_gpio >= 0 && (input & (1 << sc->reset_gpio))) { 352 /* get reset_gpio pin value */ 353 reset_pin = (value & (1 << sc->reset_gpio))?1:0; 354 if ( sc->reset_gpio_last != reset_pin ) { 355 /* 356 * if now reset is high, check how long 357 * and do reset if less than 2 seconds 358 */ 359 if ( reset_pin && 360 (time_uptime - sc->reset_gpio_ontime) < 2 ) 361 shutdown_nice(0); 362 363 sc->reset_gpio_last = reset_pin; 364 sc->reset_gpio_ontime = time_uptime; 365 } 366 } 367 368 for ( i = 0; i < NGPIO; i ++ ) 369 { 370 /* Next if output pin */ 371 if ( !(( input >> i) & 1) ) continue; 372 373 if ( (((value & input) >> i) & 1) != sc->gpio_pins[i].gp_last ) 374 { 375 /* !system=GPIO subsystem=pin7 type=PIN_HIGH period=3 */ 376 snprintf(notify , sizeof(notify ), "period=%d", 377 (uint32_t)time_uptime - sc->gpio_pins[i].gp_time); 378 snprintf(pinname, sizeof(pinname), "pin%02d", i); 379 devctl_notify("GPIO", pinname, 380 (((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", 381 notify); 382 printf("GPIO[%s] %s %s\n", pinname, 383 (((value & input) >> i) & 1)?"PIN_HIGH":"PIN_LOW", 384 notify); 385 sc->gpio_pins[i].gp_last = ((value & input) >> i) & 1; 386 sc->gpio_pins[i].gp_time = time_uptime; 387 } 388 389 } 390#endif 391 392intr_done: 393 return (FILTER_HANDLED); 394} 395 396static int 397rt305x_gpio_probe(device_t dev) 398{ 399 device_set_desc(dev, "RT305X GPIO driver"); 400 return (0); 401} 402 403static uint64_t 404rt305x_gpio_init(device_t dev) 405{ 406 uint64_t avl = ~0ULL; 407 uint32_t gmode = rt305x_sysctl_get(SYSCTL_GPIOMODE); 408 if (!(gmode & SYSCTL_GPIOMODE_RGMII_GPIO_MODE)) 409 avl &= ~RGMII_GPIO_MODE_MASK; 410 if (!(gmode & SYSCTL_GPIOMODE_SDRAM_GPIO_MODE)) 411 avl &= ~SDRAM_GPIO_MODE_MASK; 412 if (!(gmode & SYSCTL_GPIOMODE_MDIO_GPIO_MODE)) 413 avl &= ~MDIO_GPIO_MODE_MASK; 414 if (!(gmode & SYSCTL_GPIOMODE_JTAG_GPIO_MODE)) 415 avl &= ~JTAG_GPIO_MODE_MASK; 416 if (!(gmode & SYSCTL_GPIOMODE_UARTL_GPIO_MODE)) 417 avl &= ~UARTL_GPIO_MODE_MASK; 418 if (!(gmode & SYSCTL_GPIOMODE_SPI_GPIO_MODE)) 419 avl &= ~SPI_GPIO_MODE_MASK; 420 if (!(gmode & SYSCTL_GPIOMODE_I2C_GPIO_MODE)) 421 avl &= ~I2C_GPIO_MODE_MASK; 422 if ((gmode & SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO) != 423 SYSCTL_GPIOMODE_UARTF_SHARE_MODE_GPIO) 424 avl &= ~I2C_GPIO_MODE_MASK; 425/* D-Link DAP-1350 Board have 426 * MDIO_GPIO_MODE 427 * UARTF_GPIO_MODE 428 * SPI_GPIO_MODE 429 * I2C_GPIO_MODE 430 * So we have 431 * 00000001 10000000 01111111 11111110 432*/ 433 return (avl); 434 435} 436 437#define DAP1350_RESET_GPIO 10 438 439static int 440rt305x_gpio_attach(device_t dev) 441{ 442 struct rt305x_gpio_softc *sc = device_get_softc(dev); 443 int error = 0, i; 444 uint64_t avlpins = 0; 445 sc->reset_gpio = DAP1350_RESET_GPIO; 446 447 KASSERT((device_get_unit(dev) == 0), 448 ("rt305x_gpio_gpio: Only one gpio module supported")); 449 450 mtx_init(&sc->gpio_mtx, device_get_nameunit(dev), MTX_NETWORK_LOCK, 451 MTX_DEF); 452 453 /* Map control/status registers. */ 454 sc->gpio_mem_rid = 0; 455 sc->gpio_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, 456 &sc->gpio_mem_rid, RF_ACTIVE); 457 458 if (sc->gpio_mem_res == NULL) { 459 device_printf(dev, "couldn't map memory\n"); 460 error = ENXIO; 461 rt305x_gpio_detach(dev); 462 return(error); 463 } 464 465 if ((sc->gpio_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, 466 &sc->gpio_irq_rid, RF_SHAREABLE | RF_ACTIVE)) == NULL) { 467 device_printf(dev, "unable to allocate IRQ resource\n"); 468 return (ENXIO); 469 } 470 471 if ((bus_setup_intr(dev, sc->gpio_irq_res, INTR_TYPE_MISC, 472 /* rt305x_gpio_filter, */ 473 rt305x_gpio_intr, NULL, sc, &sc->gpio_ih))) { 474 device_printf(dev, 475 "WARNING: unable to register interrupt handler\n"); 476 return (ENXIO); 477 } 478 479 sc->dev = dev; 480 avlpins = rt305x_gpio_init(dev); 481 482 /* Configure all pins as input */ 483 /* disable interrupts for all pins */ 484 /* TODO */ 485 486 sc->gpio_npins = NGPIO; 487 resource_int_value(device_get_name(dev), device_get_unit(dev), 488 "pins", &sc->gpio_npins); 489 490 for (i = 0; i < sc->gpio_npins; i++) { 491 sc->gpio_pins[i].gp_pin = i; 492 sc->gpio_pins[i].gp_caps = DEFAULT_CAPS; 493 sc->gpio_pins[i].gp_flags = 0; 494 } 495 496 /* Setup reset pin interrupt */ 497 if (TUNABLE_INT_FETCH("reset_gpio", &sc->reset_gpio)) { 498 device_printf(dev, "\tHinted reset_gpio %d\n", sc->reset_gpio); 499 } 500#ifdef notyet 501 if (sc->reset_gpio != -1) { 502 rt305x_gpio_pin_setflags(dev, sc->reset_gpio, 503 GPIO_PIN_INPUT|GPIO_PIN_INVOUT| 504 GPIO_PIN_INVOUT|GPIO_PIN_REPORT); 505 device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); 506 } 507#else 508 if (sc->reset_gpio != -1) { 509 rt305x_gpio_pin_setflags(dev, sc->reset_gpio, 510 GPIO_PIN_INPUT|GPIO_PIN_INVOUT); 511 device_printf(dev, "\tUse reset_gpio %d\n", sc->reset_gpio); 512 } 513#endif 514 515 device_add_child(dev, "gpioc", device_get_unit(dev)); 516 device_add_child(dev, "gpiobus", device_get_unit(dev)); 517 518 519 return (bus_generic_attach(dev)); 520} 521 522static int 523rt305x_gpio_detach(device_t dev) 524{ 525 struct rt305x_gpio_softc *sc = device_get_softc(dev); 526 527 KASSERT(mtx_initialized(&sc->gpio_mtx), ("gpio mutex not initialized")); 528 529 bus_generic_detach(dev); 530 531 if (sc->gpio_mem_res) 532 bus_release_resource(dev, SYS_RES_MEMORY, sc->gpio_mem_rid, 533 sc->gpio_mem_res); 534 535 mtx_destroy(&sc->gpio_mtx); 536 537 return(0); 538} 539 540#ifdef notyet 541static struct resource * 542rt305x_gpio_alloc_resource(device_t bus, device_t child, int type, int *rid, 543 u_long start, u_long end, u_long count, u_int flags) 544{ 545 struct obio_softc *sc = device_get_softc(bus); 546 struct resource *rv; 547 struct rman *rm; 548 549 switch (type) { 550 case SYS_RES_GPIO: 551 rm = &sc->gpio_rman; 552 break; 553 default: 554 printf("%s: unknown resource type %d\n", __func__, type); 555 return (0); 556 } 557 558 rv = rman_reserve_resource(rm, start, end, count, flags, child); 559 if (rv == 0) { 560 printf("%s: could not reserve resource\n", __func__); 561 return (0); 562 } 563 564 rman_set_rid(rv, *rid); 565 566 return (rv); 567} 568 569static int 570rt305x_gpio_activate_resource(device_t bus, device_t child, int type, int rid, 571 struct resource *r) 572{ 573 574 return (rman_activate_resource(r)); 575} 576 577static int 578rt305x_gpio_deactivate_resource(device_t bus, device_t child, int type, int rid, 579 struct resource *r) 580{ 581 582 return (rman_deactivate_resource(r)); 583} 584 585static int 586rt305x_gpio_release_resource(device_t dev, device_t child, int type, 587 int rid, struct resource *r) 588{ 589 rman_release_resource(r); 590 return (0); 591} 592#endif 593 594static device_method_t rt305x_gpio_methods[] = { 595 DEVMETHOD(device_probe, rt305x_gpio_probe), 596 DEVMETHOD(device_attach, rt305x_gpio_attach), 597 DEVMETHOD(device_detach, rt305x_gpio_detach), 598 599 /* GPIO protocol */ 600 DEVMETHOD(gpio_pin_max, rt305x_gpio_pin_max), 601 DEVMETHOD(gpio_pin_getname, rt305x_gpio_pin_getname), 602 DEVMETHOD(gpio_pin_getflags, rt305x_gpio_pin_getflags), 603 DEVMETHOD(gpio_pin_getcaps, rt305x_gpio_pin_getcaps), 604 DEVMETHOD(gpio_pin_setflags, rt305x_gpio_pin_setflags), 605 DEVMETHOD(gpio_pin_get, rt305x_gpio_pin_get), 606 DEVMETHOD(gpio_pin_set, rt305x_gpio_pin_set), 607 DEVMETHOD(gpio_pin_toggle, rt305x_gpio_pin_toggle), 608 {0, 0}, 609}; 610 611static driver_t rt305x_gpio_driver = { 612 "gpio", 613 rt305x_gpio_methods, 614 sizeof(struct rt305x_gpio_softc), 615}; 616static devclass_t rt305x_gpio_devclass; 617 618DRIVER_MODULE(rt305x_gpio, obio, rt305x_gpio_driver, 619 rt305x_gpio_devclass, 0, 0); 620