452 lines
13 KiB
C
452 lines
13 KiB
C
/* $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 <sys/cdefs.h>
|
|
__KERNEL_RCSID(0, "$NetBSD: obio.c,v 1.19 2015/04/02 15:48:38 jmcneill Exp $");
|
|
|
|
#include <sys/param.h>
|
|
#include <sys/systm.h>
|
|
#include <sys/device.h>
|
|
|
|
#include <machine/cpu.h>
|
|
#include <sys/bus.h>
|
|
|
|
#include <arm/mainbus/mainbus.h>
|
|
#include <arm/rockchip/rockchip_reg.h>
|
|
#include <arm/rockchip/rockchip_var.h>
|
|
|
|
|
|
#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
|