Home | History | Annotate | Line # | Download | only in rockchip
rk3399_iomux.c revision 1.6.8.1
      1  1.6.8.1   thorpej /* $NetBSD: rk3399_iomux.c,v 1.6.8.1 2021/04/03 22:28:18 thorpej Exp $ */
      2      1.1  jmcneill 
      3      1.1  jmcneill /*-
      4      1.1  jmcneill  * Copyright (c) 2018 Jared McNeill <jmcneill (at) invisible.ca>
      5      1.1  jmcneill  * All rights reserved.
      6      1.1  jmcneill  *
      7      1.1  jmcneill  * Redistribution and use in source and binary forms, with or without
      8      1.1  jmcneill  * modification, are permitted provided that the following conditions
      9      1.1  jmcneill  * are met:
     10      1.1  jmcneill  * 1. Redistributions of source code must retain the above copyright
     11      1.1  jmcneill  *    notice, this list of conditions and the following disclaimer.
     12      1.1  jmcneill  * 2. Redistributions in binary form must reproduce the above copyright
     13      1.1  jmcneill  *    notice, this list of conditions and the following disclaimer in the
     14      1.1  jmcneill  *    documentation and/or other materials provided with the distribution.
     15      1.1  jmcneill  *
     16      1.1  jmcneill  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
     17      1.1  jmcneill  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
     18      1.1  jmcneill  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
     19      1.1  jmcneill  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
     20      1.1  jmcneill  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
     21      1.1  jmcneill  * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
     22      1.1  jmcneill  * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
     23      1.1  jmcneill  * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
     24      1.1  jmcneill  * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
     25      1.1  jmcneill  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
     26      1.1  jmcneill  * SUCH DAMAGE.
     27      1.1  jmcneill  */
     28      1.1  jmcneill 
     29      1.1  jmcneill //#define RK3399_IOMUX_DEBUG
     30      1.1  jmcneill 
     31      1.1  jmcneill #include <sys/cdefs.h>
     32  1.6.8.1   thorpej __KERNEL_RCSID(0, "$NetBSD: rk3399_iomux.c,v 1.6.8.1 2021/04/03 22:28:18 thorpej Exp $");
     33      1.1  jmcneill 
     34      1.1  jmcneill #include <sys/param.h>
     35      1.1  jmcneill #include <sys/bus.h>
     36      1.1  jmcneill #include <sys/device.h>
     37      1.1  jmcneill #include <sys/intr.h>
     38      1.1  jmcneill #include <sys/systm.h>
     39      1.1  jmcneill #include <sys/mutex.h>
     40      1.1  jmcneill #include <sys/kmem.h>
     41      1.1  jmcneill #include <sys/gpio.h>
     42      1.1  jmcneill #include <sys/lwp.h>
     43      1.1  jmcneill 
     44      1.1  jmcneill #include <dev/fdt/fdtvar.h>
     45      1.1  jmcneill #include <dev/fdt/syscon.h>
     46      1.1  jmcneill 
     47      1.1  jmcneill /* PU/PD control */
     48      1.1  jmcneill #define	 GRF_GPIO_P_CTL(_idx)		(0x3 << (((_idx) & 7) * 2))
     49      1.1  jmcneill #define	 GRF_GPIO_P_WRITE_EN(_idx)	(0x3 << (((_idx) & 7) * 2 + 16))
     50      1.3  jmcneill /* Different bias value mapping based on pull type of pin */
     51      1.3  jmcneill #define	  IO_DEF_GPIO_P_CTL_Z		0
     52      1.3  jmcneill #define	  IO_DEF_GPIO_P_CTL_PULLUP	1
     53      1.3  jmcneill #define	  IO_DEF_GPIO_P_CTL_PULLDOWN	2
     54      1.3  jmcneill #define	  IO_DEF_GPIO_P_CTL_RESERVED	3
     55      1.3  jmcneill #define	  IO_1V8_GPIO_P_CTL_Z		0
     56      1.3  jmcneill #define	  IO_1V8_GPIO_P_CTL_PULLDOWN	1
     57      1.3  jmcneill #define	  IO_1V8_GPIO_P_CTL_Z_ALT	2
     58      1.3  jmcneill #define	  IO_1V8_GPIO_P_CTL_PULLUP	3
     59      1.1  jmcneill 
     60      1.1  jmcneill /* Drive strength control */
     61      1.1  jmcneill /* Different drive strength value mapping for GRF and PMU registers */
     62      1.1  jmcneill #define	  GRF_GPIO_E_CTL_2MA		0
     63      1.1  jmcneill #define	  GRF_GPIO_E_CTL_4MA		1
     64      1.1  jmcneill #define	  GRF_GPIO_E_CTL_8MA		2
     65      1.1  jmcneill #define	  GRF_GPIO_E_CTL_12MA		3
     66      1.1  jmcneill #define	  PMU_GPIO_E_CTL_5MA		0
     67      1.1  jmcneill #define	  PMU_GPIO_E_CTL_10MA		1
     68      1.1  jmcneill #define	  PMU_GPIO_E_CTL_15MA		2
     69      1.1  jmcneill #define	  PMU_GPIO_E_CTL_20MA		3
     70      1.1  jmcneill 
     71      1.1  jmcneill enum rk3399_drv_type {
     72      1.1  jmcneill 	RK3399_DRV_TYPE_IO_DEFAULT,
     73      1.1  jmcneill 	RK3399_DRV_TYPE_IO_1V8_3V0,
     74      1.1  jmcneill 	RK3399_DRV_TYPE_IO_1V8,
     75      1.1  jmcneill 	RK3399_DRV_TYPE_IO_1V8_3V0_AUTO,
     76      1.1  jmcneill 	RK3399_DRV_TYPE_IO_3V3,
     77      1.1  jmcneill };
     78      1.1  jmcneill 
     79      1.1  jmcneill static int rk3399_drv_strength[5][9] = {
     80      1.1  jmcneill 	[RK3399_DRV_TYPE_IO_DEFAULT] =		{ 2, 4, 8, 12, -1 },
     81      1.1  jmcneill 	[RK3399_DRV_TYPE_IO_1V8_3V0] =		{ 3, 6, 9, 12, -1 },
     82      1.1  jmcneill 	[RK3399_DRV_TYPE_IO_1V8] =		{ 5, 10, 15, 20, -1 },
     83      1.1  jmcneill 	[RK3399_DRV_TYPE_IO_1V8_3V0_AUTO] =	{ 4, 6, 8, 10, 12, 14, 16, 18, -1 },
     84      1.1  jmcneill 	[RK3399_DRV_TYPE_IO_3V3] =		{ 4, 7, 10, 13, 16, 19, 22, 26, -1 },
     85      1.1  jmcneill };
     86      1.1  jmcneill 
     87      1.3  jmcneill enum rk3399_pull_type {
     88      1.3  jmcneill 	RK3399_PULL_TYPE_IO_DEFAULT,
     89      1.3  jmcneill 	RK3399_PULL_TYPE_IO_1V8_ONLY,
     90      1.3  jmcneill };
     91      1.3  jmcneill 
     92      1.1  jmcneill struct rk3399_iomux {
     93      1.1  jmcneill 	enum rk3399_drv_type	drv_type;
     94      1.3  jmcneill 	enum rk3399_pull_type	pull_type;
     95      1.1  jmcneill };
     96      1.1  jmcneill 
     97      1.1  jmcneill struct rk3399_iomux_bank {
     98      1.1  jmcneill 	struct rk3399_iomux	iomux[5];
     99      1.1  jmcneill 	u_int			regs;
    100      1.1  jmcneill #define	RK_IOMUX_REGS_GRF	0
    101      1.1  jmcneill #define	RK_IOMUX_REGS_PMU	1
    102      1.1  jmcneill };
    103      1.1  jmcneill 
    104      1.1  jmcneill static const struct rk3399_iomux_bank rk3399_iomux_banks[] = {
    105      1.1  jmcneill 	[0] = {
    106      1.1  jmcneill 		.regs = RK_IOMUX_REGS_PMU,
    107      1.1  jmcneill 		.iomux = {
    108      1.3  jmcneill 			[0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8,
    109      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY },
    110      1.3  jmcneill 			[1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8,
    111      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY },
    112      1.3  jmcneill 			[2] = { .drv_type = RK3399_DRV_TYPE_IO_DEFAULT,
    113      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    114      1.3  jmcneill 			[3] = { .drv_type = RK3399_DRV_TYPE_IO_DEFAULT,
    115      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    116      1.1  jmcneill 		},
    117      1.1  jmcneill 	},
    118      1.1  jmcneill 	[1] = {
    119      1.1  jmcneill 		.regs = RK_IOMUX_REGS_PMU,
    120      1.1  jmcneill 		.iomux = {
    121      1.3  jmcneill 			[0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    122      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    123      1.3  jmcneill 			[1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    124      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    125      1.3  jmcneill 			[2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    126      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    127      1.3  jmcneill 			[3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    128      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    129      1.1  jmcneill 		}
    130      1.1  jmcneill 	},
    131      1.1  jmcneill 	[2] = {
    132      1.1  jmcneill 		.regs = RK_IOMUX_REGS_GRF,
    133      1.1  jmcneill 		.iomux = {
    134      1.3  jmcneill 			[0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    135      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    136      1.3  jmcneill 			[1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    137      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    138      1.3  jmcneill 			[2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8,
    139      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY },
    140      1.3  jmcneill 			[3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8,
    141      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_1V8_ONLY },
    142      1.1  jmcneill 		},
    143      1.1  jmcneill 	},
    144      1.1  jmcneill 	[3] = {
    145      1.1  jmcneill 		.regs = RK_IOMUX_REGS_GRF,
    146      1.1  jmcneill 		.iomux = {
    147      1.3  jmcneill 			[0] = { .drv_type = RK3399_DRV_TYPE_IO_3V3,
    148      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    149      1.3  jmcneill 			[1] = { .drv_type = RK3399_DRV_TYPE_IO_3V3,
    150      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    151      1.3  jmcneill 			[2] = { .drv_type = RK3399_DRV_TYPE_IO_3V3,
    152      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    153      1.3  jmcneill 			[3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    154      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    155      1.1  jmcneill 		},
    156      1.1  jmcneill 	},
    157      1.1  jmcneill 	[4] = {
    158      1.1  jmcneill 		.regs = RK_IOMUX_REGS_GRF,
    159      1.1  jmcneill 		.iomux = {
    160      1.3  jmcneill 			[0] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    161      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    162      1.3  jmcneill 			[1] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0_AUTO,
    163      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    164      1.3  jmcneill 			[2] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    165      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    166      1.3  jmcneill 			[3] = { .drv_type = RK3399_DRV_TYPE_IO_1V8_3V0,
    167      1.3  jmcneill 				.pull_type = RK3399_PULL_TYPE_IO_DEFAULT },
    168      1.1  jmcneill 		},
    169      1.1  jmcneill 	},
    170      1.1  jmcneill };
    171      1.1  jmcneill 
    172      1.1  jmcneill #define	RK3399_IOMUX_BANK_IS_PMU(_bank)	(rk3399_iomux_banks[(_bank)].regs == RK_IOMUX_REGS_PMU)
    173      1.1  jmcneill 
    174      1.1  jmcneill struct rk3399_iomux_conf {
    175      1.1  jmcneill 	const struct rk3399_iomux_bank *banks;
    176      1.1  jmcneill 	u_int nbanks;
    177      1.1  jmcneill };
    178      1.1  jmcneill 
    179      1.1  jmcneill static const struct rk3399_iomux_conf rk3399_iomux_conf = {
    180      1.1  jmcneill 	.banks = rk3399_iomux_banks,
    181      1.1  jmcneill 	.nbanks = __arraycount(rk3399_iomux_banks),
    182      1.1  jmcneill };
    183      1.1  jmcneill 
    184  1.6.8.1   thorpej static const struct device_compatible_entry compat_data[] = {
    185  1.6.8.1   thorpej 	{ .compat = "rockchip,rk3399-pinctrl",	.data = &rk3399_iomux_conf },
    186  1.6.8.1   thorpej 	DEVICE_COMPAT_EOL
    187      1.1  jmcneill };
    188      1.1  jmcneill 
    189      1.1  jmcneill struct rk3399_iomux_softc {
    190      1.1  jmcneill 	device_t sc_dev;
    191      1.1  jmcneill 	struct syscon *sc_syscon[2];
    192      1.1  jmcneill 
    193      1.1  jmcneill 	const struct rk3399_iomux_conf *sc_conf;
    194      1.1  jmcneill };
    195      1.1  jmcneill 
    196      1.1  jmcneill #define	LOCK(syscon) 		\
    197      1.1  jmcneill 	syscon_lock(syscon)
    198      1.1  jmcneill #define	UNLOCK(syscon)		\
    199      1.1  jmcneill 	syscon_unlock(syscon)
    200      1.1  jmcneill #define	RD4(syscon, reg) 	\
    201      1.1  jmcneill 	syscon_read_4(syscon, (reg))
    202      1.1  jmcneill #define	WR4(syscon, reg, val) 	\
    203      1.1  jmcneill 	syscon_write_4(syscon, (reg), (val))
    204      1.1  jmcneill 
    205      1.1  jmcneill static int	rk3399_iomux_match(device_t, cfdata_t, void *);
    206      1.1  jmcneill static void	rk3399_iomux_attach(device_t, device_t, void *);
    207      1.1  jmcneill 
    208      1.1  jmcneill CFATTACH_DECL_NEW(rk3399_iomux, sizeof(struct rk3399_iomux_softc),
    209      1.1  jmcneill 	rk3399_iomux_match, rk3399_iomux_attach, NULL, NULL);
    210      1.1  jmcneill 
    211      1.1  jmcneill static void
    212      1.1  jmcneill rk3399_iomux_set_bias(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, int flags)
    213      1.1  jmcneill {
    214      1.1  jmcneill 	const struct rk3399_iomux_bank *banks = sc->sc_conf->banks;
    215      1.1  jmcneill 	bus_size_t reg;
    216      1.1  jmcneill 	u_int bias;
    217      1.1  jmcneill 
    218      1.1  jmcneill 	KASSERT(bank < sc->sc_conf->nbanks);
    219      1.1  jmcneill 
    220      1.1  jmcneill 	struct syscon * const syscon = sc->sc_syscon[banks[bank].regs];
    221      1.1  jmcneill 	if (RK3399_IOMUX_BANK_IS_PMU(bank)) {
    222      1.1  jmcneill 		reg = 0x00040 + (0x10 * bank);
    223      1.1  jmcneill 	} else {
    224      1.1  jmcneill 		reg = 0x0e040 + (0x10 * (bank - 2));
    225      1.1  jmcneill 	}
    226      1.1  jmcneill 	reg += 0x4 * (idx / 8);
    227      1.1  jmcneill 
    228      1.3  jmcneill 	const int pull_type = banks[bank].iomux[idx / 8].pull_type;
    229      1.3  jmcneill 
    230      1.1  jmcneill 	if (flags == GPIO_PIN_PULLUP) {
    231      1.3  jmcneill 		bias = pull_type == RK3399_PULL_TYPE_IO_DEFAULT ?
    232      1.3  jmcneill 		    IO_DEF_GPIO_P_CTL_PULLUP :
    233      1.3  jmcneill 		    IO_1V8_GPIO_P_CTL_PULLUP;
    234      1.1  jmcneill 	} else if (flags == GPIO_PIN_PULLDOWN) {
    235      1.3  jmcneill 		bias = pull_type == RK3399_PULL_TYPE_IO_DEFAULT ?
    236      1.3  jmcneill 		    IO_DEF_GPIO_P_CTL_PULLDOWN :
    237      1.3  jmcneill 		    IO_1V8_GPIO_P_CTL_PULLDOWN;
    238      1.1  jmcneill 	} else {
    239      1.3  jmcneill 		bias = pull_type == RK3399_PULL_TYPE_IO_DEFAULT ?
    240      1.3  jmcneill 		    IO_DEF_GPIO_P_CTL_Z :
    241      1.3  jmcneill 		    IO_1V8_GPIO_P_CTL_Z;
    242      1.1  jmcneill 	}
    243      1.1  jmcneill 
    244      1.1  jmcneill 	const uint32_t bias_val = __SHIFTIN(bias, GRF_GPIO_P_CTL(idx));
    245      1.1  jmcneill 	const uint32_t bias_mask = GRF_GPIO_P_WRITE_EN(idx);
    246      1.1  jmcneill 
    247      1.1  jmcneill #ifdef RK3399_IOMUX_DEBUG
    248      1.1  jmcneill 	printf("%s: bank %d idx %d flags %#x: %08x -> ", __func__, bank, idx, flags, RD4(syscon, reg));
    249      1.1  jmcneill #endif
    250      1.1  jmcneill 	WR4(syscon, reg, bias_val | bias_mask);
    251      1.1  jmcneill #ifdef RK3399_IOMUX_DEBUG
    252      1.1  jmcneill 	printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg);
    253      1.1  jmcneill #endif
    254      1.1  jmcneill }
    255      1.1  jmcneill 
    256      1.1  jmcneill static int
    257      1.1  jmcneill rk3399_iomux_map_drive_strength(struct rk3399_iomux_softc *sc, enum rk3399_drv_type drv_type, u_int val)
    258      1.1  jmcneill {
    259      1.1  jmcneill 	for (int n = 0; rk3399_drv_strength[drv_type][n] != -1; n++)
    260      1.1  jmcneill 		if (rk3399_drv_strength[drv_type][n] == val)
    261      1.1  jmcneill 			return n;
    262      1.1  jmcneill 	return -1;
    263      1.1  jmcneill }
    264      1.1  jmcneill 
    265      1.1  jmcneill static int
    266      1.1  jmcneill rk3399_iomux_set_drive_strength(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, u_int val)
    267      1.1  jmcneill {
    268      1.1  jmcneill 	const struct rk3399_iomux_bank *banks = sc->sc_conf->banks;
    269      1.1  jmcneill 	uint32_t drv_mask, drv_val;
    270      1.1  jmcneill 	bus_size_t reg;
    271      1.1  jmcneill 
    272      1.1  jmcneill 	KASSERT(bank < sc->sc_conf->nbanks);
    273      1.1  jmcneill 
    274      1.1  jmcneill 	if (idx >= 32)
    275      1.1  jmcneill 		return EINVAL;
    276      1.1  jmcneill 
    277      1.1  jmcneill 	const int drv = rk3399_iomux_map_drive_strength(sc, banks[bank].iomux[idx / 8].drv_type, val);
    278      1.1  jmcneill 	if (drv == -1)
    279      1.1  jmcneill 		return EINVAL;
    280      1.1  jmcneill 
    281      1.1  jmcneill 	struct syscon * const syscon = sc->sc_syscon[banks[bank].regs];
    282      1.1  jmcneill 	switch (bank) {
    283      1.1  jmcneill 	case 0:
    284      1.1  jmcneill 	case 1:
    285      1.1  jmcneill 		reg = 0x00040 + (0x10 * bank) + 0x4 * (idx / 4);
    286      1.1  jmcneill 		drv_mask = 0x3 << ((idx & 7) * 2);
    287      1.1  jmcneill 		break;
    288      1.1  jmcneill 	case 2:
    289      1.1  jmcneill 		reg = 0x0e100 + 0x4 * (idx / 4);
    290      1.1  jmcneill 		drv_mask = 0x3 << ((idx & 7) * 2);
    291      1.1  jmcneill 		break;
    292      1.1  jmcneill 	case 3:
    293      1.1  jmcneill 		switch (idx / 8) {
    294      1.1  jmcneill 		case 0:
    295      1.1  jmcneill 		case 1:
    296      1.1  jmcneill 		case 2:
    297      1.1  jmcneill 			reg = 0x0e110 + 0x8 * (idx / 4);
    298      1.1  jmcneill 			drv_mask = 0x7 << ((idx & 7) * 3);
    299      1.1  jmcneill 			break;
    300      1.1  jmcneill 		case 3:
    301      1.1  jmcneill 			reg = 0x0e128;
    302      1.1  jmcneill 			drv_mask = 0x3 << ((idx & 7) * 2);
    303      1.1  jmcneill 			break;
    304      1.1  jmcneill 		default:
    305      1.1  jmcneill 			return EINVAL;
    306      1.1  jmcneill 		}
    307      1.1  jmcneill 		break;
    308      1.1  jmcneill 	case 4:
    309      1.1  jmcneill 		switch (idx / 8) {
    310      1.1  jmcneill 		case 0:
    311      1.1  jmcneill 			reg = 0x0e12c;
    312      1.1  jmcneill 			drv_mask = 0x3 << ((idx & 7) * 2);
    313      1.1  jmcneill 			break;
    314      1.1  jmcneill 		case 1:
    315      1.1  jmcneill 			reg = 0x0e130;
    316      1.1  jmcneill 			drv_mask = 0x7 << ((idx & 7) * 3);
    317      1.1  jmcneill 			break;
    318      1.1  jmcneill 		case 2:
    319      1.1  jmcneill 			reg = 0x0e138;
    320      1.1  jmcneill 			drv_mask = 0x3 << ((idx & 7) * 2);
    321      1.1  jmcneill 			break;
    322      1.1  jmcneill 		case 3:
    323      1.1  jmcneill 			reg = 0x0e13c;
    324      1.1  jmcneill 			drv_mask = 0x3 << ((idx & 7) * 2);
    325      1.1  jmcneill 			break;
    326      1.1  jmcneill 		default:
    327      1.1  jmcneill 			return EINVAL;
    328      1.1  jmcneill 		}
    329      1.1  jmcneill 		break;
    330      1.1  jmcneill 	default:
    331      1.1  jmcneill 		return EINVAL;
    332      1.1  jmcneill 	}
    333      1.1  jmcneill 	drv_val = __SHIFTIN(val, drv_mask);
    334      1.1  jmcneill 
    335      1.1  jmcneill 	while (drv_mask) {
    336      1.1  jmcneill 		const uint32_t write_val = drv_val & 0xffff;
    337      1.1  jmcneill 		const uint32_t write_mask = (drv_mask & 0xffff) << 16;
    338      1.1  jmcneill 		if (write_mask) {
    339      1.1  jmcneill #ifdef RK3399_IOMUX_DEBUG
    340      1.1  jmcneill 			printf("%s: bank %d idx %d val %d: %08x -> ", __func__, bank, idx, val, RD4(syscon, reg));
    341      1.1  jmcneill #endif
    342      1.1  jmcneill 			WR4(syscon, reg, write_val | write_mask);
    343      1.1  jmcneill #ifdef RK3399_IOMUX_DEBUG
    344      1.1  jmcneill 			printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg);
    345      1.1  jmcneill #endif
    346      1.1  jmcneill 		}
    347      1.1  jmcneill 		reg += 0x4;
    348      1.1  jmcneill 		drv_val >>= 16;
    349      1.1  jmcneill 		drv_mask >>= 16;
    350      1.1  jmcneill 	}
    351      1.1  jmcneill 
    352      1.1  jmcneill 	return 0;
    353      1.1  jmcneill }
    354      1.1  jmcneill 
    355      1.1  jmcneill static void
    356      1.1  jmcneill rk3399_iomux_set_mux(struct rk3399_iomux_softc *sc, u_int bank, u_int idx, u_int mux)
    357      1.1  jmcneill {
    358      1.1  jmcneill 	const struct rk3399_iomux_bank *banks = sc->sc_conf->banks;
    359      1.1  jmcneill 	bus_size_t reg;
    360      1.1  jmcneill 	uint32_t mask;
    361      1.1  jmcneill 
    362      1.1  jmcneill 	KASSERT(bank < sc->sc_conf->nbanks);
    363      1.1  jmcneill 
    364      1.1  jmcneill 	struct syscon * const syscon = sc->sc_syscon[banks[bank].regs];
    365      1.1  jmcneill 	if (RK3399_IOMUX_BANK_IS_PMU(bank)) {
    366      1.1  jmcneill 		reg = 0x00000 + (0x10 * bank);
    367      1.1  jmcneill 	} else {
    368      1.1  jmcneill 		reg = 0x0e000 + (0x10 * (bank - 2));
    369      1.1  jmcneill 	}
    370      1.4  jmcneill 	reg += 0x4 * (idx / 8);
    371      1.1  jmcneill 	mask = 3 << ((idx & 7) * 2);
    372      1.1  jmcneill 
    373      1.1  jmcneill #ifdef RK3399_IOMUX_DEBUG
    374      1.1  jmcneill 	printf("%s: bank %d idx %d mux %#x: %08x -> ", __func__, bank, idx, mux, RD4(syscon, reg));
    375      1.1  jmcneill #endif
    376      1.1  jmcneill 	WR4(syscon, reg, (mask << 16) | __SHIFTIN(mux, mask));
    377      1.1  jmcneill #ifdef RK3399_IOMUX_DEBUG
    378      1.1  jmcneill 	printf("%08x (reg %#lx)\n", RD4(syscon, reg), reg);
    379      1.1  jmcneill #endif
    380      1.1  jmcneill }
    381      1.1  jmcneill 
    382      1.1  jmcneill static int
    383      1.1  jmcneill rk3399_iomux_config(struct rk3399_iomux_softc *sc, const int phandle, u_int bank, u_int idx, u_int mux)
    384      1.1  jmcneill {
    385      1.1  jmcneill 
    386      1.2   thorpej 	const int bias = fdtbus_pinctrl_parse_bias(phandle, NULL);
    387      1.2   thorpej 	if (bias != -1)
    388      1.2   thorpej 		rk3399_iomux_set_bias(sc, bank, idx, bias);
    389      1.2   thorpej 
    390      1.2   thorpej 	const int drv = fdtbus_pinctrl_parse_drive_strength(phandle);
    391      1.2   thorpej 	if (drv != -1 &&
    392      1.2   thorpej 	    rk3399_iomux_set_drive_strength(sc, bank, idx, drv) != 0)
    393      1.2   thorpej 		return EINVAL;
    394      1.1  jmcneill 
    395      1.2   thorpej #if notyet
    396      1.2   thorpej 	int output_value;
    397      1.2   thorpej 	const int direction =
    398      1.2   thorpej 	    fdtbus_pinctrl_parse_input_output(phandle, &output_value);
    399      1.2   thorpej 	if (direction != -1) {
    400      1.2   thorpej 		rk3399_iomux_set_direction(sc, bank, idx, direction,
    401      1.2   thorpej 		    output_value);
    402      1.1  jmcneill 	}
    403      1.1  jmcneill #endif
    404      1.1  jmcneill 
    405      1.1  jmcneill 	rk3399_iomux_set_mux(sc, bank, idx, mux);
    406      1.1  jmcneill 
    407      1.1  jmcneill 	return 0;
    408      1.1  jmcneill }
    409      1.1  jmcneill 
    410      1.1  jmcneill static int
    411      1.1  jmcneill rk3399_iomux_pinctrl_set_config(device_t dev, const void *data, size_t len)
    412      1.1  jmcneill {
    413      1.1  jmcneill 	struct rk3399_iomux_softc * const sc = device_private(dev);
    414      1.1  jmcneill 	const struct rk3399_iomux_bank *banks = sc->sc_conf->banks;
    415      1.1  jmcneill 	int pins_len;
    416      1.1  jmcneill 
    417      1.1  jmcneill 	if (len != 4)
    418      1.1  jmcneill 		return -1;
    419      1.1  jmcneill 
    420      1.1  jmcneill 	const int phandle = fdtbus_get_phandle_from_native(be32dec(data));
    421      1.1  jmcneill 	const u_int *pins = fdtbus_get_prop(phandle, "rockchip,pins", &pins_len);
    422      1.1  jmcneill 
    423      1.1  jmcneill 	while (pins_len >= 16) {
    424      1.1  jmcneill 		const u_int bank = be32toh(pins[0]);
    425      1.1  jmcneill 		const u_int idx = be32toh(pins[1]);
    426      1.1  jmcneill 		const u_int mux = be32toh(pins[2]);
    427      1.1  jmcneill 		const int cfg = fdtbus_get_phandle_from_native(be32toh(pins[3]));
    428      1.1  jmcneill 
    429      1.1  jmcneill 		struct syscon * const syscon = sc->sc_syscon[banks[bank].regs];
    430      1.1  jmcneill 		LOCK(syscon);
    431      1.1  jmcneill 		rk3399_iomux_config(sc, cfg, bank, idx, mux);
    432      1.1  jmcneill 		UNLOCK(syscon);
    433      1.1  jmcneill 
    434      1.1  jmcneill 		pins_len -= 16;
    435      1.1  jmcneill 		pins += 4;
    436      1.1  jmcneill 	}
    437      1.1  jmcneill 
    438      1.1  jmcneill 	return 0;
    439      1.1  jmcneill }
    440      1.1  jmcneill 
    441      1.1  jmcneill static struct fdtbus_pinctrl_controller_func rk3399_iomux_pinctrl_funcs = {
    442      1.1  jmcneill 	.set_config = rk3399_iomux_pinctrl_set_config,
    443      1.1  jmcneill };
    444      1.1  jmcneill 
    445      1.1  jmcneill static int
    446      1.1  jmcneill rk3399_iomux_match(device_t parent, cfdata_t cf, void *aux)
    447      1.1  jmcneill {
    448      1.1  jmcneill 	struct fdt_attach_args * const faa = aux;
    449      1.1  jmcneill 
    450  1.6.8.1   thorpej 	return of_compatible_match(faa->faa_phandle, compat_data);
    451      1.1  jmcneill }
    452      1.1  jmcneill 
    453      1.5       tnn #ifdef RK3399_IOMUX_FORCE_ENABLE_SWJ_DP
    454      1.5       tnn /*
    455      1.5       tnn  * This enables the SWJ-DP (Serial Wire JTAG Debug Port).
    456      1.5       tnn  * If you enable this you must also disable sdhc due to pin conflicts.
    457      1.5       tnn  */
    458      1.5       tnn static void
    459      1.5       tnn rk3399_iomux_force_enable_swj_dp(struct rk3399_iomux_softc * const sc)
    460      1.5       tnn {
    461      1.5       tnn 	struct syscon * const syscon = sc->sc_syscon[RK_IOMUX_REGS_GRF];
    462      1.5       tnn 	uint32_t val;
    463      1.5       tnn 
    464      1.5       tnn 	aprint_normal_dev(sc->sc_dev, "enabling on-chip debugging\n");
    465      1.5       tnn #define GRF_GPIO4B_IOMUX	0xe024
    466      1.5       tnn #define GRF_GPIO4B_IOMUX_TCK	__BITS(5,4)
    467      1.5       tnn #define GRF_GPIO4B_IOMUX_TMS	__BITS(7,6)
    468      1.5       tnn #define GRF_SOC_CON7		0xe21c
    469      1.5       tnn #define GRF_SOC_CON7_FORCE_JTAG	__BIT(12)
    470      1.5       tnn 	LOCK(syscon);
    471      1.5       tnn 	val = RD4(syscon, GRF_GPIO4B_IOMUX);
    472      1.5       tnn 	val &= ~(GRF_GPIO4B_IOMUX_TCK | GRF_GPIO4B_IOMUX_TMS);
    473      1.5       tnn 	val |= __SHIFTIN(0x2, GRF_GPIO4B_IOMUX_TCK);
    474      1.5       tnn 	val |= __SHIFTIN(0x2, GRF_GPIO4B_IOMUX_TMS);
    475      1.5       tnn 	WR4(syscon, GRF_GPIO4B_IOMUX, val);
    476      1.5       tnn 	val = RD4(syscon, GRF_SOC_CON7);
    477      1.5       tnn 	val |= GRF_SOC_CON7_FORCE_JTAG;
    478      1.5       tnn 	WR4(syscon, GRF_SOC_CON7, val);
    479      1.5       tnn 	UNLOCK(syscon);
    480      1.5       tnn }
    481      1.5       tnn #endif
    482      1.5       tnn 
    483      1.1  jmcneill static void
    484      1.1  jmcneill rk3399_iomux_attach(device_t parent, device_t self, void *aux)
    485      1.1  jmcneill {
    486      1.1  jmcneill 	struct rk3399_iomux_softc * const sc = device_private(self);
    487      1.1  jmcneill 	struct fdt_attach_args * const faa = aux;
    488      1.1  jmcneill 	const int phandle = faa->faa_phandle;
    489      1.1  jmcneill 	int child, sub;
    490      1.1  jmcneill 
    491      1.1  jmcneill 	sc->sc_dev = self;
    492      1.1  jmcneill 	sc->sc_syscon[RK_IOMUX_REGS_GRF] = fdtbus_syscon_acquire(phandle, "rockchip,grf");
    493      1.1  jmcneill 	if (sc->sc_syscon[RK_IOMUX_REGS_GRF] == NULL) {
    494      1.1  jmcneill 		aprint_error(": couldn't acquire grf syscon\n");
    495      1.1  jmcneill 		return;
    496      1.1  jmcneill 	}
    497      1.1  jmcneill 	sc->sc_syscon[RK_IOMUX_REGS_PMU] = fdtbus_syscon_acquire(phandle, "rockchip,pmu");
    498      1.1  jmcneill 	if (sc->sc_syscon[RK_IOMUX_REGS_PMU] == NULL) {
    499      1.1  jmcneill 		aprint_error(": couldn't acquire pmu syscon\n");
    500      1.1  jmcneill 		return;
    501      1.1  jmcneill 	}
    502  1.6.8.1   thorpej 	sc->sc_conf = of_compatible_lookup(phandle, compat_data)->data;
    503      1.1  jmcneill 
    504      1.1  jmcneill 	aprint_naive("\n");
    505      1.1  jmcneill 	aprint_normal(": RK3399 IOMUX control\n");
    506      1.1  jmcneill 
    507      1.1  jmcneill 	for (child = OF_child(phandle); child; child = OF_peer(child)) {
    508      1.1  jmcneill 		for (sub = OF_child(child); sub; sub = OF_peer(sub)) {
    509      1.1  jmcneill 			if (!of_hasprop(sub, "rockchip,pins"))
    510      1.1  jmcneill 				continue;
    511      1.1  jmcneill 			fdtbus_register_pinctrl_config(self, sub, &rk3399_iomux_pinctrl_funcs);
    512      1.1  jmcneill 		}
    513      1.1  jmcneill 	}
    514      1.1  jmcneill 
    515      1.1  jmcneill 	for (child = OF_child(phandle); child; child = OF_peer(child)) {
    516      1.1  jmcneill 		struct fdt_attach_args cfaa = *faa;
    517      1.1  jmcneill 		cfaa.faa_phandle = child;
    518      1.1  jmcneill 		cfaa.faa_name = fdtbus_get_string(child, "name");
    519      1.1  jmcneill 		cfaa.faa_quiet = false;
    520      1.1  jmcneill 
    521      1.1  jmcneill 		config_found(self, &cfaa, NULL);
    522      1.1  jmcneill 	}
    523      1.5       tnn 
    524      1.5       tnn #ifdef RK3399_IOMUX_FORCE_ENABLE_SWJ_DP
    525      1.5       tnn 	rk3399_iomux_force_enable_swj_dp(sc);
    526      1.5       tnn #endif
    527      1.1  jmcneill }
    528