/* $NetBSD: obio.c,v 1.19 2015/04/02 15:48:38 jmcneill Exp $ */ /* * Copyright (c) 2001, 2002, 2003 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL WASABI SYSTEMS, INC * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE * POSSIBILITY OF SUCH DAMAGE. */ #include "opt_rockchip.h" #include __KERNEL_RCSID(0, "$NetBSD: obio.c,v 1.19 2015/04/02 15:48:38 jmcneill Exp $"); #include #include #include #include #include #include #include #include #include "locators.h" int obio_match(device_t, cfdata_t, void *); void obio_attach(device_t, device_t, void *); CFATTACH_DECL_NEW(obio, 0, obio_match, obio_attach, NULL, NULL); int obio_print(void *, const char *); int obio_search(device_t, cfdata_t, const int *, void *); static void obio_init_rk3066(void); static void obio_init_rk3188(void); static void obio_grf_set(uint32_t, uint32_t); static int obio_gpio_set_out(u_int, u_int, u_int); #ifdef ROCKCHIP_CLOCK_DEBUG static void obio_dump_clocks(void); #endif /* there can be only one */ bool obio_found; int obio_match(device_t parent, cfdata_t cf, void *aux) { if (obio_found) return 0; return 1; } void obio_attach(device_t parent, device_t self, void *aux) { obio_found = true; aprint_naive("\n"); aprint_normal(": %s\n", rockchip_chip_name()); #ifdef ROCKCHIP_CLOCK_DEBUG obio_dump_clocks(); #endif switch (rockchip_chip_id()) { case ROCKCHIP_CHIP_ID_RK3066: obio_init_rk3066(); break; case ROCKCHIP_CHIP_ID_RK3188: case ROCKCHIP_CHIP_ID_RK3188PLUS: obio_init_rk3188(); break; default: break; } /* * Attach all on-board devices as described in the kernel * configuration file. Attach devices marked "crit 1" first. */ for (int crit = 1; crit >= 0; crit--) { config_search_ia(obio_search, self, "obio", &crit); } } int obio_print(void *aux, const char *pnp) { struct obio_attach_args *obio = aux; bus_addr_t addr = obio->obio_base + obio->obio_offset; aprint_normal(": addr 0x%08lx", addr); aprint_normal("-0x%08lx", addr + (obio->obio_size - 1)); if (obio->obio_width != OBIOCF_WIDTH_DEFAULT) aprint_normal(" width %d", obio->obio_width); if (obio->obio_intr != OBIOCF_INTR_DEFAULT) aprint_normal(" intr %d", obio->obio_intr); if (obio->obio_mult != OBIOCF_MULT_DEFAULT) aprint_normal(" mult %d", obio->obio_mult); if (obio->obio_port != OBIOCF_PORT_DEFAULT) aprint_normal(" port %d", obio->obio_port); return UNCONF; } int obio_search(device_t parent, cfdata_t cf, const int *ldesc, void *aux) { struct obio_attach_args obio; bus_addr_t addr = cf->cf_loc[OBIOCF_ADDR]; int crit = *(int *)aux; if (cf->cf_loc[OBIOCF_CRIT] != crit) return 0; if (addr >= ROCKCHIP_CORE0_BASE && addr < ROCKCHIP_CORE0_BASE + ROCKCHIP_CORE0_SIZE) { obio.obio_base = ROCKCHIP_CORE0_BASE; obio.obio_bsh = rockchip_core0_bsh; } else if (addr >= ROCKCHIP_CORE1_BASE && addr < ROCKCHIP_CORE1_BASE + ROCKCHIP_CORE1_SIZE) { obio.obio_base = ROCKCHIP_CORE1_BASE; obio.obio_bsh = rockchip_core1_bsh; } else { panic("addr %#llx is not in CORE0 or CORE1 space", (long long unsigned int)addr); } obio.obio_offset = addr - obio.obio_base; obio.obio_size = cf->cf_loc[OBIOCF_SIZE]; obio.obio_width = cf->cf_loc[OBIOCF_WIDTH]; obio.obio_intr = cf->cf_loc[OBIOCF_INTR]; obio.obio_mult = cf->cf_loc[OBIOCF_MULT]; obio.obio_port = cf->cf_loc[OBIOCF_PORT]; obio.obio_dmat = &rockchip_bus_dma_tag; bus_space_subregion(&armv7_generic_bs_tag, rockchip_core1_bsh, ROCKCHIP_GRF_OFFSET, ROCKCHIP_GRF_SIZE, &obio.obio_grf_bsh); switch (cf->cf_loc[OBIOCF_MULT]) { case 1: obio.obio_bst = &armv7_generic_bs_tag; break; case 4: obio.obio_bst = &armv7_generic_a4x_bs_tag; break; default: panic("Unsupported EMIFS multiplier."); break; } if (config_match(parent, cf, &obio) > 0) { config_attach(parent, cf, &obio, obio_print); } return 0; } #define GRF_GPIO0A_IOMUX_OFFSET 0x00a8 #define GRF_GPIO0B_IOMUX_OFFSET 0x00ac #define GRF_GPIO0C_IOMUX_OFFSET 0x00b0 #define GRF_GPIO0D_IOMUX_OFFSET 0x00b4 #define GRF_GPIO1A_IOMUX_OFFSET 0x00b8 #define GRF_GPIO1B_IOMUX_OFFSET 0x00bc #define GRF_GPIO1C_IOMUX_OFFSET 0x00c0 #define GRF_GPIO1D_IOMUX_OFFSET 0x00c4 #define GRF_GPIO2A_IOMUX_OFFSET 0x00c8 #define GRF_GPIO2B_IOMUX_OFFSET 0x00cc #define GRF_GPIO2C_IOMUX_OFFSET 0x00d0 #define GRF_GPIO2D_IOMUX_OFFSET 0x00d4 #define GRF_GPIO3A_IOMUX_OFFSET 0x00d8 #define GRF_GPIO3B_IOMUX_OFFSET 0x00dc #define GRF_GPIO3C_IOMUX_OFFSET 0x00e0 #define GRF_GPIO3D_IOMUX_OFFSET 0x00e4 #define GRF_GPIO4A_IOMUX_OFFSET 0x00e8 #define GRF_GPIO4B_IOMUX_OFFSET 0x00ec #define GRF_GPIO4C_IOMUX_OFFSET 0x00f0 #define GRF_GPIO4D_IOMUX_OFFSET 0x00f4 #define GRF_GPIO6B_IOMUX_OFFSET 0x010c #define GRF_SOC_CON0_OFFSET 0x0150 #define GRF_SOC_CON1_OFFSET 0x0154 #define GRF_SOC_CON2_OFFSET 0x0158 static void obio_init_rk3066(void) { /* dwctwo[01] */ obio_grf_set(GRF_GPIO0A_IOMUX_OFFSET, 0x14001400); /* com2 */ obio_grf_set(GRF_GPIO1B_IOMUX_OFFSET, 0x00050005); /* rkemac0 */ obio_grf_set(GRF_GPIO1C_IOMUX_OFFSET, 0xffffaaaa); obio_grf_set(GRF_GPIO1D_IOMUX_OFFSET, 0x000f000a); obio_grf_set(GRF_SOC_CON1_OFFSET, 0x00030002); obio_grf_set(GRF_SOC_CON2_OFFSET, 0x00400040); /* rkiic[01234] */ obio_grf_set(GRF_GPIO2D_IOMUX_OFFSET, 0x55005500); obio_grf_set(GRF_GPIO3A_IOMUX_OFFSET, 0x05550555); obio_grf_set(GRF_SOC_CON1_OFFSET, 0xf800f800); /* dwcmmc0 */ obio_grf_set(GRF_GPIO3A_IOMUX_OFFSET, 0x50004000); obio_grf_set(GRF_GPIO3B_IOMUX_OFFSET, 0x55551555); /* ChipSPARK Rayeager PX2: dwcmmc2 */ obio_grf_set(GRF_GPIO3D_IOMUX_OFFSET, 0xc0008000); obio_grf_set(GRF_GPIO4B_IOMUX_OFFSET, 0x003c0008); obio_grf_set(GRF_SOC_CON0_OFFSET, 0x08000800); /* ChipSPARK Rayeager PX2: umass0 */ obio_grf_set(GRF_GPIO0B_IOMUX_OFFSET, 0x04000000); obio_grf_set(GRF_GPIO4C_IOMUX_OFFSET, 0x30000000); obio_gpio_set_out(0, 13, 1); obio_gpio_set_out(4, 22, 1); /* ChipSPARK Rayeager PX2: uhub2 */ obio_grf_set(GRF_GPIO1D_IOMUX_OFFSET, 0x40000000); obio_gpio_set_out(1, 31, 1); /* ChipSPARK Rayeager PX2: ukphy0 */ /* rtl8201f: clock must be configured before resetting */ rockchip_mac_set_rate(50000000); obio_grf_set(GRF_GPIO1D_IOMUX_OFFSET, 0x10000000); obio_gpio_set_out(1, 30, 1); /* rtl8201f: need 1s delay here? */ } #define RK3188_GRF_GPIO0C_IOMUX_OFFSET 0x0068 #define RK3188_GRF_GPIO0D_IOMUX_OFFSET 0x006c #define RK3188_GRF_GPIO1A_IOMUX_OFFSET 0x0070 #define RK3188_GRF_GPIO1B_IOMUX_OFFSET 0x0074 #define RK3188_GRF_GPIO1C_IOMUX_OFFSET 0x0078 #define RK3188_GRF_GPIO1D_IOMUX_OFFSET 0x007c #define RK3188_GRF_GPIO2A_IOMUX_OFFSET 0x0080 #define RK3188_GRF_GPIO2B_IOMUX_OFFSET 0x0084 #define RK3188_GRF_GPIO2C_IOMUX_OFFSET 0x0088 #define RK3188_GRF_GPIO2D_IOMUX_OFFSET 0x008c #define RK3188_GRF_GPIO3A_IOMUX_OFFSET 0x0090 #define RK3188_GRF_GPIO3B_IOMUX_OFFSET 0x0094 #define RK3188_GRF_GPIO3C_IOMUX_OFFSET 0x0098 #define RK3188_GRF_GPIO3D_IOMUX_OFFSET 0x009c #define RK3188_GRF_SOC_CON0_OFFSET 0x00a0 #define RK3188_GRF_SOC_CON1_OFFSET 0x00a4 #define RK3188_GRF_SOC_CON2_OFFSET 0x00a8 #define RK3188_GRF_IO_CON2_OFFSET 0x00fc #define RK3188_GRF_IO_CON3_OFFSET 0x0100 static void obio_init_rk3188(void) { /* com2 */ obio_grf_set(RK3188_GRF_GPIO1B_IOMUX_OFFSET, 0x000f0005); /* rkiic[01234] */ obio_grf_set(RK3188_GRF_GPIO1D_IOMUX_OFFSET, 0x55555555); obio_grf_set(RK3188_GRF_GPIO3B_IOMUX_OFFSET, 0xa000a000); obio_grf_set(RK3188_GRF_SOC_CON1_OFFSET, 0xf800f800); /* dwcmmc0 */ obio_grf_set(RK3188_GRF_GPIO3A_IOMUX_OFFSET, 0x55555554); obio_grf_set(RK3188_GRF_GPIO3B_IOMUX_OFFSET, 0x00050001); //obio_grf_set(RK3188_GRF_IO_CON2_OFFSET, 0x00c000c0); /* rkemac0 */ obio_grf_set(RK3188_GRF_GPIO3C_IOMUX_OFFSET, 0xffffaaaa); obio_grf_set(RK3188_GRF_GPIO3D_IOMUX_OFFSET, 0x000f000a); obio_grf_set(RK3188_GRF_SOC_CON1_OFFSET, 0x00030002); obio_grf_set(RK3188_GRF_SOC_CON2_OFFSET, 0x00400040); obio_grf_set(RK3188_GRF_IO_CON3_OFFSET, 0x000f000f); /* dwcotg[01] */ obio_grf_set(RK3188_GRF_GPIO3D_IOMUX_OFFSET, 0x3c003c00); /* Radxa Rock: dwcotg[01] */ //obio_grf_set(RK3188_GRF_GPIO3D_IOMUX_OFFSET, 0x3c000000); obio_grf_set(RK3188_GRF_GPIO2D_IOMUX_OFFSET, 0x40000000); obio_gpio_set_out(0, 3, 1); obio_gpio_set_out(2, 31, 1); /* Radxa Rock: IT66121 HDMI */ obio_gpio_set_out(3, 10, 1); /* Radxa Rock: ukphy0 */ obio_gpio_set_out(3, 26, 1); /* XXX: RMII_INT, input, active low */ /* Minix Neo X7: cdce0 */ obio_gpio_set_out(0, 30, 1); } static void obio_grf_set(uint32_t offset, uint32_t value) { bus_space_handle_t bh; bus_space_tag_t bt = &armv7_generic_bs_tag; uint32_t old, new; bus_space_subregion(bt, rockchip_core1_bsh, ROCKCHIP_GRF_OFFSET, ROCKCHIP_GRF_SIZE, &bh); old = bus_space_read_4(bt, bh, offset); bus_space_write_4(bt, bh, offset, value); new = bus_space_read_4(bt, bh, offset); printf("grf: %04x: 0x%08x 0x%08x -> 0x%08x\n", offset, old, value, new); } #define GPIO_SWPORTA_DR_OFFSET 0x00 #define GPIO_SWPORTA_DDR_OFFSET 0x04 static int obio_gpio_set_out(u_int unit, u_int pin, u_int value) { bus_space_handle_t bh; bus_space_tag_t bt = &armv7_generic_bs_tag; uint32_t gpio_base = 0, gpio_size = 0; uint32_t old, new; switch (rockchip_chip_id()) { case ROCKCHIP_CHIP_ID_RK3066: switch (unit) { case 0: gpio_base = ROCKCHIP_GPIO0_OFFSET; gpio_size = ROCKCHIP_GPIO0_SIZE; break; case 1: gpio_base = ROCKCHIP_GPIO1_OFFSET; gpio_size = ROCKCHIP_GPIO1_SIZE; break; case 2: gpio_base = ROCKCHIP_GPIO2_OFFSET; gpio_size = ROCKCHIP_GPIO2_SIZE; break; case 3: gpio_base = ROCKCHIP_GPIO3_OFFSET; gpio_size = ROCKCHIP_GPIO3_SIZE; break; case 4: gpio_base = ROCKCHIP_GPIO4_OFFSET; gpio_size = ROCKCHIP_GPIO4_SIZE; break; case 6: gpio_base = ROCKCHIP_GPIO6_OFFSET; gpio_size = ROCKCHIP_GPIO6_SIZE; break; } break; case ROCKCHIP_CHIP_ID_RK3188: case ROCKCHIP_CHIP_ID_RK3188PLUS: switch (unit) { case 0: gpio_base = ROCKCHIP_RK3188_GPIO0_OFFSET; gpio_size = ROCKCHIP_RK3188_GPIO0_SIZE; break; case 1: gpio_base = ROCKCHIP_GPIO1_OFFSET; gpio_size = ROCKCHIP_GPIO1_SIZE; break; case 2: gpio_base = ROCKCHIP_GPIO2_OFFSET; gpio_size = ROCKCHIP_GPIO2_SIZE; break; case 3: gpio_base = ROCKCHIP_GPIO3_OFFSET; gpio_size = ROCKCHIP_GPIO3_SIZE; break; } break; } if (gpio_base == 0 || gpio_size == 0 || pin > 31) return EINVAL; bus_space_subregion(bt, rockchip_core1_bsh, gpio_base, gpio_size, &bh); old = bus_space_read_4(bt, bh, GPIO_SWPORTA_DR_OFFSET); if (value) new = old | __BIT(pin); else new = old & ~__BIT(pin); bus_space_write_4(bt, bh, GPIO_SWPORTA_DR_OFFSET, new); new = bus_space_read_4(bt, bh, GPIO_SWPORTA_DR_OFFSET); printf("gpio%d: dr 0x%08x -> 0x%08x\n", unit, old, new); old = bus_space_read_4(bt, bh, GPIO_SWPORTA_DDR_OFFSET); bus_space_write_4(bt, bh, GPIO_SWPORTA_DDR_OFFSET, old | __BIT(pin)); new = bus_space_read_4(bt, bh, GPIO_SWPORTA_DDR_OFFSET); printf("gpio%d: ddr 0x%08x -> 0x%08x\n", unit, old, new); return 0; } #ifdef ROCKCHIP_CLOCK_DEBUG static void obio_dump_clocks(void) { printf("APLL: %u Hz\n", rockchip_apll_get_rate()); printf("CPLL: %u Hz\n", rockchip_cpll_get_rate()); printf("DPLL: %u Hz\n", rockchip_dpll_get_rate()); printf("GPLL: %u Hz\n", rockchip_gpll_get_rate()); printf("CPU: %u Hz\n", rockchip_cpu_get_rate()); printf("AHB: %u Hz\n", rockchip_ahb_get_rate()); printf("APB: %u Hz\n", rockchip_apb_get_rate()); printf("PCLK_CPU: %u Hz\n", rockchip_pclk_cpu_get_rate()); printf("A9PERIPH: %u Hz\n", rockchip_a9periph_get_rate()); } #endif