2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
4 * Copyright (c) 2018 Emmanuel Vadot <manu@FreeBSD.org>
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
33 #include <sys/param.h>
34 #include <sys/systm.h>
37 #include <sys/kernel.h>
38 #include <sys/module.h>
41 #include <sys/mutex.h>
43 #include <machine/bus.h>
44 #include <machine/resource.h>
45 #include <machine/intr.h>
47 #include <dev/fdt/simplebus.h>
49 #include <dev/ofw/ofw_bus.h>
50 #include <dev/ofw/ofw_bus_subr.h>
52 #include <dev/fdt/fdt_pinctrl.h>
54 #include <dev/extres/syscon/syscon.h>
56 #include "syscon_if.h"
60 struct rk_pinctrl_pin_drive {
68 struct rk_pinctrl_bank {
75 struct rk_pinctrl_pin_fixup {
84 struct rk_pinctrl_softc;
86 struct rk_pinctrl_conf {
87 struct rk_pinctrl_bank *iomux_conf;
88 uint32_t iomux_nbanks;
89 struct rk_pinctrl_pin_fixup *pin_fixup;
91 struct rk_pinctrl_pin_drive *pin_drive;
93 uint32_t (*get_pd_offset)(struct rk_pinctrl_softc *, uint32_t);
94 struct syscon *(*get_syscon)(struct rk_pinctrl_softc *, uint32_t);
97 struct rk_pinctrl_softc {
98 struct simplebus_softc simplebus_sc;
102 struct rk_pinctrl_conf *conf;
105 static struct rk_pinctrl_bank rk3328_iomux_bank[] = {
204 static struct rk_pinctrl_pin_fixup rk3328_pin_fixup[] = {
228 #define RK_PINDRIVE(_bank, _subbank, _offset, _value, _ma) \
231 .subbank = _subbank, \
237 static struct rk_pinctrl_pin_drive rk3328_pin_drive[] = {
238 RK_PINDRIVE(0, 0, 0x200, 0, 2)
239 RK_PINDRIVE(0, 0, 0x200, 1, 4)
240 RK_PINDRIVE(0, 0, 0x200, 2, 8)
241 RK_PINDRIVE(0, 0, 0x200, 3, 12)
243 RK_PINDRIVE(0, 1, 0x204, 0, 2)
244 RK_PINDRIVE(0, 1, 0x204, 1, 4)
245 RK_PINDRIVE(0, 1, 0x204, 2, 8)
246 RK_PINDRIVE(0, 1, 0x204, 3, 12)
248 RK_PINDRIVE(0, 2, 0x208, 0, 2)
249 RK_PINDRIVE(0, 2, 0x208, 1, 4)
250 RK_PINDRIVE(0, 2, 0x208, 2, 8)
251 RK_PINDRIVE(0, 2, 0x208, 3, 12)
253 RK_PINDRIVE(0, 3, 0x20C, 0, 2)
254 RK_PINDRIVE(0, 3, 0x20C, 1, 4)
255 RK_PINDRIVE(0, 3, 0x20C, 2, 8)
256 RK_PINDRIVE(0, 3, 0x20C, 3, 12)
258 RK_PINDRIVE(1, 0, 0x210, 0, 2)
259 RK_PINDRIVE(1, 0, 0x210, 1, 4)
260 RK_PINDRIVE(1, 0, 0x210, 2, 8)
261 RK_PINDRIVE(1, 0, 0x210, 3, 12)
263 RK_PINDRIVE(1, 1, 0x214, 0, 2)
264 RK_PINDRIVE(1, 1, 0x214, 1, 4)
265 RK_PINDRIVE(1, 1, 0x214, 2, 8)
266 RK_PINDRIVE(1, 1, 0x214, 3, 12)
268 RK_PINDRIVE(1, 2, 0x218, 0, 2)
269 RK_PINDRIVE(1, 2, 0x218, 1, 4)
270 RK_PINDRIVE(1, 2, 0x218, 2, 8)
271 RK_PINDRIVE(1, 2, 0x218, 3, 12)
273 RK_PINDRIVE(1, 3, 0x21C, 0, 2)
274 RK_PINDRIVE(1, 3, 0x21C, 1, 4)
275 RK_PINDRIVE(1, 3, 0x21C, 2, 8)
276 RK_PINDRIVE(1, 3, 0x21C, 3, 12)
278 RK_PINDRIVE(2, 0, 0x220, 0, 2)
279 RK_PINDRIVE(2, 0, 0x220, 1, 4)
280 RK_PINDRIVE(2, 0, 0x220, 2, 8)
281 RK_PINDRIVE(2, 0, 0x220, 3, 12)
283 RK_PINDRIVE(2, 1, 0x224, 0, 2)
284 RK_PINDRIVE(2, 1, 0x224, 1, 4)
285 RK_PINDRIVE(2, 1, 0x224, 2, 8)
286 RK_PINDRIVE(2, 1, 0x224, 3, 12)
288 RK_PINDRIVE(2, 2, 0x228, 0, 2)
289 RK_PINDRIVE(2, 2, 0x228, 1, 4)
290 RK_PINDRIVE(2, 2, 0x228, 2, 8)
291 RK_PINDRIVE(2, 2, 0x228, 3, 12)
293 RK_PINDRIVE(2, 3, 0x22C, 0, 2)
294 RK_PINDRIVE(2, 3, 0x22C, 1, 4)
295 RK_PINDRIVE(2, 3, 0x22C, 2, 8)
296 RK_PINDRIVE(2, 3, 0x22C, 3, 12)
298 RK_PINDRIVE(3, 0, 0x230, 0, 2)
299 RK_PINDRIVE(3, 0, 0x230, 1, 4)
300 RK_PINDRIVE(3, 0, 0x230, 2, 8)
301 RK_PINDRIVE(3, 0, 0x230, 3, 12)
303 RK_PINDRIVE(3, 1, 0x234, 0, 2)
304 RK_PINDRIVE(3, 1, 0x234, 1, 4)
305 RK_PINDRIVE(3, 1, 0x234, 2, 8)
306 RK_PINDRIVE(3, 1, 0x234, 3, 12)
308 RK_PINDRIVE(3, 2, 0x238, 0, 2)
309 RK_PINDRIVE(3, 2, 0x238, 1, 4)
310 RK_PINDRIVE(3, 2, 0x238, 2, 8)
311 RK_PINDRIVE(3, 2, 0x238, 3, 12)
313 RK_PINDRIVE(3, 3, 0x23C, 0, 2)
314 RK_PINDRIVE(3, 3, 0x23C, 1, 4)
315 RK_PINDRIVE(3, 3, 0x23C, 2, 8)
316 RK_PINDRIVE(3, 3, 0x23C, 3, 12)
320 rk3328_get_pd_offset(struct rk_pinctrl_softc *sc, uint32_t bank)
325 static struct syscon *
326 rk3328_get_syscon(struct rk_pinctrl_softc *sc, uint32_t bank)
331 struct rk_pinctrl_conf rk3328_conf = {
332 .iomux_conf = rk3328_iomux_bank,
333 .iomux_nbanks = nitems(rk3328_iomux_bank),
334 .pin_fixup = rk3328_pin_fixup,
335 .npin_fixup = nitems(rk3328_pin_fixup),
336 .pin_drive = rk3328_pin_drive,
337 .npin_drive = nitems(rk3328_pin_drive),
338 .get_pd_offset = rk3328_get_pd_offset,
339 .get_syscon = rk3328_get_syscon,
342 static struct rk_pinctrl_bank rk3399_iomux_bank[] = {
465 static struct rk_pinctrl_pin_fixup rk3399_pin_fixup[] = {};
467 static struct rk_pinctrl_pin_drive rk3399_pin_drive[] = {
469 RK_PINDRIVE(0, 0, 0x80, 0, 5)
470 RK_PINDRIVE(0, 0, 0x80, 1, 10)
471 RK_PINDRIVE(0, 0, 0x80, 2, 15)
472 RK_PINDRIVE(0, 0, 0x80, 3, 20)
475 RK_PINDRIVE(0, 1, 0x88, 0, 5)
476 RK_PINDRIVE(0, 1, 0x88, 1, 10)
477 RK_PINDRIVE(0, 1, 0x88, 2, 15)
478 RK_PINDRIVE(0, 1, 0x88, 3, 20)
481 RK_PINDRIVE(1, 0, 0xA0, 0, 3)
482 RK_PINDRIVE(1, 0, 0xA0, 1, 6)
483 RK_PINDRIVE(1, 0, 0xA0, 2, 9)
484 RK_PINDRIVE(1, 0, 0xA0, 3, 12)
487 RK_PINDRIVE(1, 1, 0xA8, 0, 3)
488 RK_PINDRIVE(1, 1, 0xA8, 1, 6)
489 RK_PINDRIVE(1, 1, 0xA8, 2, 9)
490 RK_PINDRIVE(1, 1, 0xA8, 3, 12)
493 RK_PINDRIVE(1, 2, 0xB0, 0, 3)
494 RK_PINDRIVE(1, 2, 0xB0, 1, 6)
495 RK_PINDRIVE(1, 2, 0xB0, 2, 9)
496 RK_PINDRIVE(1, 2, 0xB0, 3, 12)
499 RK_PINDRIVE(1, 3, 0xB8, 0, 3)
500 RK_PINDRIVE(1, 3, 0xB8, 1, 6)
501 RK_PINDRIVE(1, 3, 0xB8, 2, 9)
502 RK_PINDRIVE(1, 3, 0xB8, 3, 12)
506 rk3399_get_pd_offset(struct rk_pinctrl_softc *sc, uint32_t bank)
514 static struct syscon *
515 rk3399_get_syscon(struct rk_pinctrl_softc *sc, uint32_t bank)
523 struct rk_pinctrl_conf rk3399_conf = {
524 .iomux_conf = rk3399_iomux_bank,
525 .iomux_nbanks = nitems(rk3399_iomux_bank),
526 .pin_fixup = rk3399_pin_fixup,
527 .npin_fixup = nitems(rk3399_pin_fixup),
528 .pin_drive = rk3399_pin_drive,
529 .npin_drive = nitems(rk3399_pin_drive),
530 .get_pd_offset = rk3399_get_pd_offset,
531 .get_syscon = rk3399_get_syscon,
534 static struct ofw_compat_data compat_data[] = {
535 #ifdef SOC_ROCKCHIP_RK3328
536 {"rockchip,rk3328-pinctrl", (uintptr_t)&rk3328_conf},
538 #ifdef SOC_ROCKCHIP_RK3399
539 {"rockchip,rk3399-pinctrl", (uintptr_t)&rk3399_conf},
545 rk_pinctrl_parse_bias(phandle_t node)
547 if (OF_hasprop(node, "bias-disable"))
549 if (OF_hasprop(node, "bias-pull-up"))
551 if (OF_hasprop(node, "bias-pull-down"))
557 static int rk_pinctrl_parse_drive(struct rk_pinctrl_softc *sc, phandle_t node,
558 uint32_t bank, uint32_t subbank, uint32_t *drive, uint32_t *offset)
563 if (OF_getencprop(node, "drive-strength", &value,
567 /* Map to the correct drive value */
568 for (i = 0; i < sc->conf->npin_drive; i++) {
569 if (sc->conf->pin_drive[i].bank != bank &&
570 sc->conf->pin_drive[i].subbank != subbank)
572 if (sc->conf->pin_drive[i].ma == value) {
573 *drive = sc->conf->pin_drive[i].value;
582 rk_pinctrl_get_fixup(struct rk_pinctrl_softc *sc, uint32_t bank, uint32_t pin,
583 uint32_t *reg, uint32_t *mask, uint32_t *bit)
587 for (i = 0; i < sc->conf->npin_fixup; i++)
588 if (sc->conf->pin_fixup[i].bank == bank &&
589 sc->conf->pin_fixup[i].pin == pin) {
590 *reg = sc->conf->pin_fixup[i].reg;
591 *mask = sc->conf->pin_fixup[i].mask;
592 *bit = sc->conf->pin_fixup[i].bit;
599 rk_pinctrl_configure_pin(struct rk_pinctrl_softc *sc, uint32_t *pindata)
602 struct syscon *syscon;
603 uint32_t bank, subbank, pin, function, bias;
604 uint32_t bit, mask, reg, drive;
609 function = pindata[2];
610 pin_conf = OF_node_from_xref(pindata[3]);
613 for (i = 0; i < sc->conf->iomux_nbanks; i++)
614 if (sc->conf->iomux_conf[i].bank_num == bank &&
615 sc->conf->iomux_conf[i].subbank_num == subbank)
618 if (i == sc->conf->iomux_nbanks) {
619 device_printf(sc->dev, "Unknown pin %d in bank %d\n", pin,
625 syscon = sc->conf->get_syscon(sc, bank);
627 /* Parse pin function */
628 reg = sc->conf->iomux_conf[i].offset;
629 switch (sc->conf->iomux_conf[i].nbits) {
633 bit = (pin % 8 % 5) * 3;
634 mask = (0x7 << bit) << 16;
639 mask = (0x3 << bit) << 16;
642 rk_pinctrl_get_fixup(sc, bank, pin, ®, &mask, &bit);
643 SYSCON_WRITE_4(syscon, reg, function << bit | mask);
646 bias = rk_pinctrl_parse_bias(pin_conf);
648 reg = sc->conf->get_pd_offset(sc, bank);
650 reg += bank * 0x10 + ((pin / 8) * 0x4);
652 mask = (0x3 << bit) << 16;
653 SYSCON_WRITE_4(syscon, reg, bias << bit | mask);
657 if (rk_pinctrl_parse_drive(sc, pin_conf, bank, subbank, &drive, ®) == 0) {
659 mask = (0x3 << bit) << 16;
660 SYSCON_WRITE_4(syscon, reg, bias << bit | mask);
665 rk_pinctrl_configure_pins(device_t dev, phandle_t cfgxref)
667 struct rk_pinctrl_softc *sc;
672 sc = device_get_softc(dev);
673 node = OF_node_from_xref(cfgxref);
675 npins = OF_getencprop_alloc_multi(node, "rockchip,pins", sizeof(*pins),
680 for (i = 0; i != npins; i += 4)
681 rk_pinctrl_configure_pin(sc, pins + i);
687 rk_pinctrl_probe(device_t dev)
690 if (!ofw_bus_status_okay(dev))
693 if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0)
696 device_set_desc(dev, "RockChip Pinctrl controller");
697 return (BUS_PROBE_DEFAULT);
701 rk_pinctrl_attach(device_t dev)
703 struct rk_pinctrl_softc *sc;
707 sc = device_get_softc(dev);
710 node = ofw_bus_get_node(dev);
712 if (OF_hasprop(node, "rockchip,grf") &&
713 syscon_get_by_ofw_property(dev, node,
714 "rockchip,grf", &sc->grf) != 0) {
715 device_printf(dev, "cannot get grf driver handle\n");
719 // RK3399 has banks in PMU. RK3328 does not have a PMU.
720 if (ofw_bus_node_is_compatible(node, "rockchip,rk3399-pinctrl")) {
721 if (OF_hasprop(node, "rockchip,pmu") &&
722 syscon_get_by_ofw_property(dev, node,
723 "rockchip,pmu", &sc->pmu) != 0) {
724 device_printf(dev, "cannot get pmu driver handle\n");
729 sc->conf = (struct rk_pinctrl_conf *)ofw_bus_search_compatible(dev,
730 compat_data)->ocd_data;
732 fdt_pinctrl_register(dev, "rockchip,pins");
733 fdt_pinctrl_configure_tree(dev);
735 simplebus_init(dev, node);
737 bus_generic_probe(dev);
739 /* Attach child devices */
740 for (node = OF_child(node); node > 0; node = OF_peer(node)) {
741 if (!ofw_bus_node_is_compatible(node, "rockchip,gpio-bank"))
743 cdev = simplebus_add_device(dev, node, 0, NULL, -1, NULL);
745 device_probe_and_attach(cdev);
748 return (bus_generic_attach(dev));
752 rk_pinctrl_detach(device_t dev)
758 static device_method_t rk_pinctrl_methods[] = {
759 /* Device interface */
760 DEVMETHOD(device_probe, rk_pinctrl_probe),
761 DEVMETHOD(device_attach, rk_pinctrl_attach),
762 DEVMETHOD(device_detach, rk_pinctrl_detach),
764 /* fdt_pinctrl interface */
765 DEVMETHOD(fdt_pinctrl_configure,rk_pinctrl_configure_pins),
770 static devclass_t rk_pinctrl_devclass;
772 DEFINE_CLASS_1(rk_pinctrl, rk_pinctrl_driver, rk_pinctrl_methods,
773 sizeof(struct rk_pinctrl_softc), simplebus_driver);
775 EARLY_DRIVER_MODULE(rk_pinctrl, simplebus, rk_pinctrl_driver,
776 rk_pinctrl_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE);
777 MODULE_VERSION(rk_pinctrl, 1);