diff options
author | Patrick Wildt <patrick@cvs.openbsd.org> | 2013-09-04 14:38:50 +0000 |
---|---|---|
committer | Patrick Wildt <patrick@cvs.openbsd.org> | 2013-09-04 14:38:50 +0000 |
commit | 6bbb01e146782eed471c94cbe2563ae8b59d1b8b (patch) | |
tree | 367a031eac776c18fc2f1d73bf86cb60576272b1 /sys/arch/armv7/omap | |
parent | d33bef10c2430729f5df07f3a6eca73a8f3f5d1f (diff) |
In the future, we shouldn't have one port port ARM SoC, that's just
ridiculous. This is the first step for a common and generic ARM port
for ARMv7 SoCs.
Diffstat (limited to 'sys/arch/armv7/omap')
32 files changed, 11165 insertions, 0 deletions
diff --git a/sys/arch/armv7/omap/am335x.c b/sys/arch/armv7/omap/am335x.c new file mode 100644 index 00000000000..4ab39623c1d --- /dev/null +++ b/sys/arch/armv7/omap/am335x.c @@ -0,0 +1,180 @@ +/* $OpenBSD: am335x.c,v 1.1 2013/09/04 14:38:29 patrick Exp $ */ + +/* + * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org> + * Copyright (c) 2013 Raphael Graf <r@undefined.ch> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <machine/bus.h> + +#include <armv7/omap/omapvar.h> + +#define PRCM_SIZE 0x2000 +#define PRCM_ADDR 0x44E00000 + +#define SCM_SIZE 0x2000 +#define SCM_ADDR 0x44E10000 + +#define INTC_SIZE 0x300 +#define INTC_ADDR 0x48200000 + +#define DMTIMERx_SIZE 0x80 +#define DMTIMER0_ADDR 0x44E05000 +#define DMTIMER1_ADDR 0x44E31000 /* 1MS */ +#define DMTIMER2_ADDR 0x48040000 +#define DMTIMER3_ADDR 0x48042000 +#define DMTIMER4_ADDR 0x48044000 +#define DMTIMER5_ADDR 0x48046000 +#define DMTIMER6_ADDR 0x48048000 +#define DMTIMER7_ADDR 0x4804A000 +#define DMTIMER0_IRQ 66 +#define DMTIMER1_IRQ 67 +#define DMTIMER2_IRQ 68 +#define DMTIMER3_IRQ 69 +#define DMTIMER4_IRQ 92 +#define DMTIMER5_IRQ 93 +#define DMTIMER6_IRQ 94 +#define DMTIMER7_IRQ 95 + +#define WD_SIZE 0x80 +#define WD_ADDR 0x44E35000 +#define WD_IRQ 91 + +#define GPIOx_SIZE 0x200 +#define GPIO0_ADDR 0x44E07000 +#define GPIO1_ADDR 0x4804C000 +#define GPIO2_ADDR 0x481AC000 +#define GPIO3_ADDR 0x481AE000 +#define GPIO0_IRQ 96 +#define GPIO1_IRQ 98 +#define GPIO2_IRQ 32 +#define GPIO3_IRQ 62 + +#define UARTx_SIZE 0x90 +#define UART0_ADDR 0x44E09000 +#define UART1_ADDR 0x48022000 +#define UART2_ADDR 0x48024000 +#define UART3_ADDR 0x481A6000 +#define UART4_ADDR 0x481A8000 +#define UART5_ADDR 0x481AA000 +#define UART0_IRQ 72 +#define UART1_IRQ 73 +#define UART2_IRQ 74 +#define UART3_IRQ 44 +#define UART4_IRQ 45 +#define UART5_IRQ 46 + +#define HSMMCx_SIZE 0x300 +#define HSMMC0_ADDR 0x48060000 +#define HSMMC0_IRQ 64 + +#define CPSW_SIZE 0x4000 +#define CPSW_ADDR 0x4A100000 +#define CPSW_IRQ 40 + +struct omap_dev am335x_devs[] = { + + /* + * Power, Reset and Clock Manager + */ + + { .name = "prcm", + .unit = 0, + .mem = { { PRCM_ADDR, PRCM_SIZE } }, + }, + + /* + * System Control Module + */ + + { .name = "sitaracm", + .unit = 0, + .mem = { { SCM_ADDR, SCM_SIZE } }, + }, + + /* + * Interrupt Controller + */ + + { .name = "intc", + .unit = 0, + .mem = { { INTC_ADDR, INTC_SIZE } }, + }, + + /* + * General Purpose Timers + */ + + { .name = "dmtimer", + .unit = 0, + .mem = { { DMTIMER2_ADDR, DMTIMERx_SIZE } }, + .irq = { DMTIMER2_IRQ } + }, + + { .name = "dmtimer", + .unit = 1, + .mem = { { DMTIMER3_ADDR, DMTIMERx_SIZE } }, + .irq = { DMTIMER3_IRQ } + }, + + /* + * Watchdog Timer + */ + + { .name = "omdog", + .unit = 0, + .mem = { { WD_ADDR, WD_SIZE } } + }, + + /* + * UART + */ + + { .name = "com", + .unit = 0, + .mem = { { UART0_ADDR, UARTx_SIZE } }, + .irq = { UART0_IRQ } + }, + + /* + * MMC + */ + + { .name = "ommmc", + .unit = 0, + .mem = { { HSMMC0_ADDR, HSMMCx_SIZE } }, + .irq = { HSMMC0_IRQ } + }, + + /* cpsw Ethernet */ + { .name = "cpsw", + .unit = 0, + .mem = { { CPSW_ADDR, CPSW_SIZE } }, + .irq = { CPSW_IRQ } + }, + + /* Terminator */ + { .name = NULL, + .unit = 0 + } +}; + +void +am335x_init(void) +{ + omap_set_devs(am335x_devs); +} diff --git a/sys/arch/armv7/omap/am335x_cm_padconf.c b/sys/arch/armv7/omap/am335x_cm_padconf.c new file mode 100644 index 00000000000..3723b99165c --- /dev/null +++ b/sys/arch/armv7/omap/am335x_cm_padconf.c @@ -0,0 +1,350 @@ +/* $OpenBSD: am335x_cm_padconf.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* $NetBSD: am335x_cm_padconf.c,v 1.2 2013/05/06 18:53:40 rkujawa Exp $ */ +/*- + * Copyright (c) 2012 Damjan Marion <dmarion@FreeBSD.org> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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 <sys/cdefs.h> + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/gpio.h> +#include <armv7/omap/sitara_cm.h> + +#define _PIN(r, b, gp, gm, m0, m1, m2, m3, m4, m5, m6, m7) \ + { .reg_off = r, \ + .gpio_pin = gp, \ + .gpio_mode = gm, \ + .ballname = b, \ + .muxmodes[0] = m0, \ + .muxmodes[1] = m1, \ + .muxmodes[2] = m2, \ + .muxmodes[3] = m3, \ + .muxmodes[4] = m4, \ + .muxmodes[5] = m5, \ + .muxmodes[6] = m6, \ + .muxmodes[7] = m7, \ + } + +#define SLEWCTRL (0x01 << 6) /* faster(0) or slower(1) slew rate. */ +#define RXACTIVE (0x01 << 5) /* Input enable value for the Pad */ +#define PULLTYPESEL (0x01 << 4) /* Pad pullup/pulldown type selection */ +#define PULLUDEN (0x01 << 3) /* Pullup/pulldown disabled */ + +#define PADCONF_OUTPUT (0) +#define PADCONF_OUTPUT_PULLUP (PULLTYPESEL) +#define PADCONF_INPUT (RXACTIVE | PULLUDEN) +#define PADCONF_INPUT_PULLUP (RXACTIVE | PULLTYPESEL) +#define PADCONF_INPUT_PULLDOWN (RXACTIVE) +#define PADCONF_INPUT_PULLUP_SLOW (PADCONF_INPUT_PULLUP | SLEWCTRL) + +const struct sitara_cm_padstate ti_padstate_devmap[] = { + {"output", PADCONF_OUTPUT }, + {"output_pullup", PADCONF_OUTPUT_PULLUP }, + {"input", PADCONF_INPUT }, + {"input_pulldown", PADCONF_INPUT_PULLDOWN }, + {"input_pullup", PADCONF_INPUT_PULLUP }, + {"i2c", PADCONF_INPUT_PULLUP_SLOW }, + { .state = NULL } +}; + +const struct sitara_cm_padconf ti_padconf_devmap[] = { + _PIN(0x800, "GPMC_AD0", 32, 7,"gpmc_ad0", "mmc1_dat0", NULL, NULL, NULL, NULL, NULL, "gpio1_0"), + _PIN(0x804, "GPMC_AD1", 33, 7,"gpmc_ad1", "mmc1_dat1", NULL, NULL, NULL, NULL, NULL, "gpio1_1"), + _PIN(0x808, "GPMC_AD2", 34, 7,"gpmc_ad2", "mmc1_dat2", NULL, NULL, NULL, NULL, NULL, "gpio1_2"), + _PIN(0x80C, "GPMC_AD3", 35, 7,"gpmc_ad3", "mmc1_dat3", NULL, NULL, NULL, NULL, NULL, "gpio1_3"), + _PIN(0x810, "GPMC_AD4", 36, 7,"gpmc_ad4", "mmc1_dat4", NULL, NULL, NULL, NULL, NULL, "gpio1_4"), + _PIN(0x814, "GPMC_AD5", 37, 7,"gpmc_ad5", "mmc1_dat5", NULL, NULL, NULL, NULL, NULL, "gpio1_5"), + _PIN(0x818, "GPMC_AD6", 38, 7,"gpmc_ad6", "mmc1_dat6", NULL, NULL, NULL, NULL, NULL, "gpio1_6"), + _PIN(0x81C, "GPMC_AD7", 39, 7,"gpmc_ad7", "mmc1_dat7", NULL, NULL, NULL, NULL, NULL, "gpio1_7"), + _PIN(0x820, "GPMC_AD8", 22, 7, "gpmc_ad8", "lcd_data23", "mmc1_dat0", "mmc2_dat4", "ehrpwm2A", NULL, NULL, "gpio0_22"), + _PIN(0x824, "GPMC_AD9", 23, 7, "gpmc_ad9", "lcd_data22", "mmc1_dat1", "mmc2_dat5", "ehrpwm2B", NULL, NULL, "gpio0_23"), + _PIN(0x828, "GPMC_AD10", 26, 7, "gpmc_ad10", "lcd_data21", "mmc1_dat2", "mmc2_dat6", "ehrpwm2_tripzone_in", NULL, NULL, "gpio0_26"), + _PIN(0x82C, "GPMC_AD11", 27, 7, "gpmc_ad11", "lcd_data20", "mmc1_dat3", "mmc2_dat7", "ehrpwm0_synco", NULL, NULL, "gpio0_27"), + _PIN(0x830, "GPMC_AD12", 44, 7, "gpmc_ad12", "lcd_data19", "mmc1_dat4", "mmc2_dat0", "eQEP2A_in", "pr1_mii0_txd2", "pr1_pru0_pru_r30_14", "gpio1_12"), + _PIN(0x834, "GPMC_AD13", 45, 7, "gpmc_ad13", "lcd_data18", "mmc1_dat5", "mmc2_dat1", "eQEP2B_in", "pr1_mii0_txd1", "pr1_pru0_pru_r30_15", "gpio1_13"), + _PIN(0x838, "GPMC_AD14", 46, 7, "gpmc_ad14", "lcd_data17", "mmc1_dat6", "mmc2_dat2", "eQEP2_index", "pr1_mii0_txd0", "pr1_pru0_pru_r31_14", "gpio1_14"), + _PIN(0x83C, "GPMC_AD15", 47, 7, "gpmc_ad15", "lcd_data16", "mmc1_dat7", "mmc2_dat3", "eQEP2_strobe", "pr1_ecap0_ecap_capin_apwm_o", "pr1_pru0_pru_r31_15", "gpio1_15"), + _PIN(0x840, "GPMC_A0", 48, 7, "gpmc_a0", "gmii2_txen", "rgmii2_tctl", "rmii2_txen", "gpmc_a16", "pr1_mii_mt1_clk", "ehrpwm1_tripzone_input", "gpio1_16"), + _PIN(0x844, "GPMC_A1", 49, 7, "gpmc_a1", "gmii2_rxdv", "rgmii2_rctl", "mmc2_dat0", "gpmc_a17", "pr1_mii1_txd3", "ehrpwm0_synco", "gpio1_17"), + _PIN(0x848, "GPMC_A2", 50, 7, "gpmc_a2", "gmii2_txd3", "rgmii2_td3", "mmc2_dat1", "gpmc_a18", "pr1_mii1_txd2", "ehrpwm1A", "gpio1_18"), + _PIN(0x84C, "GPMC_A3", 51, 7, "gpmc_a3", "gmii2_txd2", "rgmii2_td2", "mmc2_dat2", "gpmc_a19", "pr1_mii1_txd1", "ehrpwm1B", "gpio1_19"), + _PIN(0x850, "GPMC_A4", 52, 7, "gpmc_a4", "gmii2_txd1", "rgmii2_td1", "rmii2_tdx1", "gpmc_a20", "pr1_mii1_txd0", "eQEP1A_in", "gpio1_20"), + _PIN(0x854, "GPMC_A5", 53, 7, "gpmc_a5", "gmii2_txd0", "rgmii2_td0", "rmii2_txd0", "gpmc_a21", "pr1_mii1_rxd3", "eQEP1B_in", "gpio1_21"), + _PIN(0x858, "GPMC_A6", 54, 7, "gpmc_a6", "gmii2_txclk", "rgmii2_tclk", "mmc2_dat4", "gpmc_a22", "pr1_mii1_rxd2", "eQEP1_index", "gpio1_22"), + _PIN(0x85C, "GPMC_A7", 55, 7, "gpmc_a7", "gmii2_rxclk", "rgmii2_rclk", "mmc2_dat5", "gpmc_a23", "pr1_mii1_rxd1", "eQEP1_strobe", "gpio1_23"), + _PIN(0x860, "GPMC_A8", 56, 7, "gpmc_a8", "gmii2_rxd3", "rgmii2_rd3", "mmc2_dat6", "gpmc_a24", "pr1_mii1_rxd0", "mcasp0_aclkx", "gpio1_24"), + _PIN(0x864, "GPMC_A9", 57, 7, "gmpc_a9", "gmii2_rxd2", "rgmii2_rd2", "mmc2_dat7 / rmii2_crs_dv", "gpmc_a25", "pr1_mii_mr1_clk", "mcasp0_fsx", "gpio1_25"), + _PIN(0x868, "GPMC_A10", 58, 7, "gmpc_a10", "gmii2_rxd1", "rgmii2_rd1", "rmii2_rxd1", "gpmc_a26", "pr1_mii1_rxdv", "mcasp0_arx0", "gpio1_26"), + _PIN(0x86C, "GPMC_A11", 59, 7, "gmpc_a11", "gmii2_rxd0", "rgmii2_rd0", "rmii2_rxd0", "gpmc_a27", "pr1_mii1_rxer", "mcasp0_axr1", "gpio1_27"), + _PIN(0x870, "GPMC_WAIT0", 30, 7, "gpmc_wait0", "gmii2_crs", "gpmc_csn4", "rmii2_crs_dv", "mmc1_sdcd", "pr1_mii1_col", "uart4_rxd", "gpio0_30"), + _PIN(0x874, "GPMC_WPn", 31, 7, "gpmc_wpn", "gmii2_rxerr", "gpmc_csn5", "rmii2_rxerr", "mmc2_sdcd", "pr1_mii1_txen", "uart4_txd", "gpio0_31"), + _PIN(0x878, "GPMC_BEn1", 60, 7, "gpmc_be1n", "gmii2_col", "gmpc_csn6","mmc2_dat3", "gpmc_dir", "pr1_mii1_rxlink", "mcasp0_aclkr", "gpio1_28"), + _PIN(0x87c, "GPMC_CSn0", 61, 7, "gpmc_csn0", NULL, NULL, NULL, NULL, NULL, NULL, "gpio1_29"), + _PIN(0x880, "GPMC_CSn1", 62, 7, "gpmc_csn1", "gpmc_clk", "mmc1_clk", "pr1_edio_data_in6", "pr1_edio_data_out6", "pr1_pru1_pru_r30_12", "pr1_pru1_pru_r31_12", "gpio1_30"), + _PIN(0x884, "GPMC_CSn2", 63, 7, "gpmc_csn2", "gpmc_be1n", "mmc1_cmd", "pr1_edio_data_in7", "pr1_edio_data_out7", "pr1_pru1_pru_r30_13", "pr1_pru1_pru_r31_13", "gpio1_31"), + _PIN(0x888, "GPMC_CSn3", 64, 7, "gpmc_csn3", "gpmc_a3", "rmii2_crs_dv", "mmc2_cmd", "pr1_mii0_crs", "pr1_mdio_data", "EMU4", "gpio2_0"), + _PIN(0x88c, "GPMC_CLK", 65, 7, "gpmc_clk", "lcd_memory_clk", "gpmc_wait1", "mmc2_clk", "pr1_mii1_crs", "pr1_mdio_mdclk", "mcasp0_fsr", "gpio2_1"), + _PIN(0x890, "GPMC_ADVn_ALE", 66, 7, "gpmc_advn_ale", NULL, "timer4", NULL, NULL, NULL, NULL, "gpio2_2"), + _PIN(0x894, "GPMC_OEn_REn", 67, 7, "gpmc_oen_ren", NULL, "timer7", NULL, NULL, NULL, NULL, "gpio2_3"), + _PIN(0x898, "GPMC_WEn", 68, 7, "gpmc_wen", NULL, "timer6", NULL, NULL, NULL, NULL, "gpio2_4"), + _PIN(0x89c, "GPMC_BEn0_CLE", 67, 7, "gpmc_ben0_cle", NULL, "timer5", NULL, NULL, NULL, NULL, "gpio2_5"), + _PIN(0x8a0, "LCD_DATA0", 68, 7, "lcd_data0", "gpmc_a0", "pr1_mii_mt0_clk", "ehrpwm2A", NULL, "pr1_pru1_pru_r30_0", "pr1_pru1_pru_r31_0", "gpio2_6"), + _PIN(0x8a4, "LCD_DATA1", 69, 7, "lcd_data1", "gpmc_a1", "pr1_mii0_txen", "ehrpwm2B", NULL, "pr1_pru1_pru_r30_1", "pr1_pru1_pru_r31_1", "gpio2_7"), + _PIN(0x8a8, "LCD_DATA2", 70, 7, "lcd_data2", "gpmc_a2", "pr1_mii0_txd3", "ehrpwm2_tripzone_input", NULL, "pr1_pru1_pru_r30_2", "pr1_pru1_pru_r31_2", "gpio2_8"), + _PIN(0x8ac, "LCD_DATA3", 71, 7, "lcd_data3", "gpmc_a3", "pr1_mii0_txd2", "ehrpwm0_synco", NULL, "pr1_pru1_pru_r30_3", "pr1_pru1_pru_r31_3", "gpio2_9"), + _PIN(0x8b0, "LCD_DATA4", 72, 7, "lcd_data4", "gpmc_a4", "pr1_mii0_txd1", "eQEP2A_in", NULL, "pr1_pru1_pru_r30_4", "pr1_pru1_pru_r31_4", "gpio2_10"), + _PIN(0x8b4, "LCD_DATA5", 73, 7, "lcd_data5", "gpmc_a5", "pr1_mii0_txd0", "eQEP2B_in", NULL, "pr1_pru1_pru_r30_5", "pr1_pru1_pru_r31_5", "gpio2_11"), + _PIN(0x8b8, "LCD_DATA6", 74, 7, "lcd_data6", "gpmc_a6", "pr1_edio_data_in6", "eQEP2_index", "pr1_edio_data_out6", "pr1_pru1_pru_r30_6", "pr1_pru1_pru_r31_6", "gpio2_12"), + _PIN(0x8bc, "LCD_DATA7", 75, 7, "lcd_data7", "gpmc_a7", "pr1_edio_data_in7", "eQEP2_strobe", "pr1_edio_data_out7", "pr1_pru1_pru_r30_7", "pr1_pru1_pru_r31_7", "gpio2_13"), + _PIN(0x8c0, "LCD_DATA8", 76, 7, "lcd_data8", "gpmc_a12", "ehrpwm1_tripzone_input", "mcasp0_aclkx", "uart5_txd", "pr1_mii0_rxd3", "uart2_ctsn", "gpio2_14"), + _PIN(0x8c4, "LCD_DATA9", 76, 7, "lcd_data9", "gpmc_a13", "ehrpwm0_synco", "mcasp0_fsx", "uart5_rxd", "pr1_mii0_rxd2", "uart2_rtsn", "gpio2_15"), + _PIN(0x8c8, "LCD_DATA10", 77, 7, "lcd_data10", "gpmc_a14", "ehrpwm1A", "mcasp0_axr0", NULL, "pr1_mii0_rxd1", "uart3_ctsn", "gpio2_16"), + _PIN(0x8cc, "LCD_DATA11", 78, 7, "lcd_data11", "gpmc_a15", "ehrpwm1B", "mcasp0_ahclkr", "mcasp0_axr2", "pr1_mii0_rxd0", "uart3_rtsn", "gpio2_17"), + _PIN(0x8d0, "LCD_DATA12", 8, 7, "lcd_data12", "gpmc_a16", "eQEP1A_in", "mcasp0_aclkr", "mcasp0_axr2", "pr1_mii0_rxlink", "uart4_ctsn", "gpio0_8"), + _PIN(0x8d4, "LCD_DATA13", 9, 7, "lcd_data13", "gpmc_a17", "eQEP1B_in", "mcasp0_fsr", "mcasp0_axr3", "pr1_mii0_rxer", "uart4_rtsn", "gpio0_9"), + _PIN(0x8d8, "LCD_DATA14", 10, 7, "lcd_data14", "gpmc_a18", "eQEP1_index", "mcasp0_axr1", "uart5_rxd", "pr1_mii_mr0_clk", "uart5_ctsn", "gpio0_10"), + _PIN(0x8dc, "LCD_DATA15", 11, 7, "lcd_data15", "gpmc_a19", "eQEP1_strobe", "mcasp0_ahclkx", "mcasp0_axr3", "pr1_mii0_rxdv", "uart5_rtsn", "gpio0_11"), + _PIN(0x8e0, "LCD_VSYNC", 86, 7, "lcd_vsync", "gpmc_a8", "gpmc_a1", "pr1_edio_data_in2", "pr1_edio_data_out2", "pr1_pru1_pru_r30_8", "pr1_pru1_pru_r31_8", "gpio2_22"), + _PIN(0x8e4, "LCD_HSYNC", 87, 7, "lcd_hsync", "gmpc_a9", "gpmc_a2", "pr1_edio_data_in3", "pr1_edio_data_out3", "pr1_pru1_pru_r30_9", "pr1_pru1_pru_r31_9", "gpio2_23"), + _PIN(0x8e8, "LCD_PCLK", 88, 7, "lcd_pclk", "gpmc_a10", "pr1_mii0_crs", "pr1_edio_data_in4", "pr1_edio_data_out4", "pr1_pru1_pru_r30_10", "pr1_pru1_pru_r31_10", "gpio2_24"), + _PIN(0x8ec, "LCD_AC_BIAS_EN", 89, 7, "lcd_ac_bias_en", "gpmc_a11", "pr1_mii1_crs", "pr1_edio_data_in5", "pr1_edio_data_out5", "pr1_pru1_pru_r30_11", "pr1_pru1_pru_r31_11", "gpio2_25"), + _PIN(0x8f0, "MMC0_DAT3", 90, 7, "mmc0_dat3", "gpmc_a20", "uart4_ctsn", "timer5", "uart1_dcdn", "pr1_pru0_pru_r30_8", "pr1_pru0_pru_r31_8", "gpio2_26"), + _PIN(0x8f4, "MMC0_DAT2", 91, 7, "mmc0_dat2", "gpmc_a21", "uart4_rtsn", "timer6", "uart1_dsrn", "pr1_pru0_pru_r30_9", "pr1_pru0_pru_r31_9", "gpio2_27"), + _PIN(0x8f8, "MMC0_DAT1", 92, 7, "mmc0_dat1", "gpmc_a22", "uart5_ctsn", "uart3_rxd", "uart1_dtrn", "pr1_pru0_pru_r30_10", "pr1_pru0_pru_r31_10", "gpio2_28"), + _PIN(0x8fc, "MMC0_DAT0", 93, 7, "mmc0_dat0", "gpmc_a23", "uart5_rtsn", "uart3_txd", "uart1_rin", "pr1_pru0_pru_r30_11", "pr1_pru0_pru_r31_11", "gpio2_29"), + _PIN(0x900, "MMC0_CLK", 94, 7, "mmc0_clk", "gpmc_a24", "uart3_ctsn", "uart2_rxd", "dcan1_tx", "pr1_pru0_pru_r30_12", "pr1_pru0_pru_r31_12", "gpio2_30"), + _PIN(0x904, "MMC0_CMD", 95, 7, "mmc0_cmd", "gpmc_a25", "uart3_rtsn", "uart2_txd", "dcan1_rx", "pr1_pru0_pru_r30_13", "pr1_pru0_pru_r31_13", "gpio2_31"), + _PIN(0x908, "MII1_COL", 96, 7, "gmii1_col", "rmii2_refclk", "spi1_sclk", "uart5_rxd", "mcasp1_axr2", "mmc2_dat3", "mcasp0_axr2", "gpio3_0"), + _PIN(0x90c, "MII1_CRS", 97, 7, "gmii1_crs", "rmii1_crs_dv", "spi1_d0", "I2C1_SDA", "mcasp1_aclkx", "uart5_ctsn", "uart2_rxd", "gpio3_1"), + _PIN(0x910, "MII1_RX_ER", 98, 7, "gmii1_rxerr", "rmii1_rxerr", "spi1_d1", "I2C1_SCL", "mcasp1_fsx", "uart5_rtsn", "uart2_txd", "gpio3_2"), + _PIN(0x914, "MII1_TX_EN", 99, 7, "gmii1_txen", "rmii1_txen", "rgmii1_tctl", "timer4", "mcasp1_axr0", "eQEP0_index", "mmc2_cmd", "gpio3_3"), + _PIN(0x918, "MII1_RX_DV", 100, 7, "gmii1_rxdv", "cd_memory_clk", "rgmii1_rctl", "uart5_txd", "mcasp1_aclkx", "mmc2_dat0", "mcasp0_aclkr", "gpio3_4"), + _PIN(0x91c, "MII1_TXD3", 16, 7, "gmii1_txd3", "dcan0_tx", "rgmii1_td3", "uart4_rxd", "mcasp1_fsx", "mmc2_dat1", "mcasp0_fsr", "gpio0_16"), + _PIN(0x920, "MII1_TXD2", 17, 7, "gmii1_txd2", "dcan0_rx", "rgmii1_td2", "uart4_txd", "mcasp1_axr0", "mmc2_dat2", "mcasp0_ahclkx", "gpio0_17"), + _PIN(0x924, "MII1_TXD1", 21, 7, "gmii1_txd1", "rmii1_txd1", "rgmii1_td1", "mcasp1_fsr", "mcasp1_axr1", "eQEP0A_in", "mmc1_cmd", "gpio0_21"), + _PIN(0x928, "MII1_TXD0", 28, 7, "gmii1_txd0", "rmii1_txd0", "rgmii1_td0", "mcasp1_axr2", "mcasp1_aclkr", "eQEP0B_in", "mmc1_clk", "gpio0_28"), + _PIN(0x92c, "MII1_TX_CLK", 105, 7, "gmii1_txclk", "uart2_rxd", "rgmii1_tclk", "mmc0_dat7", "mmc1_dat0", "uart1_dcdn", "mcasp0_aclkx", "gpio3_9"), + _PIN(0x930, "MII1_RX_CLK", 106, 7, "gmii1_rxclk", "uart2_txd", "rgmii1_rclk", "mmc0_dat6", "mmc1_dat1", "uart1_dsrn", "mcasp0_fsx", "gpio3_10"), + _PIN(0x934, "MII1_RXD3", 82, 7, "gmii1_rxd3", "uart3_rxd", "rgmii1_rd3", "mmc0_dat5", "mmc1_dat2", "uart1_dtrn", "mcasp0_axr0", "gpio2_18"), + _PIN(0x938, "MII1_RXD2", 83, 7, "gmii1_rxd2", "uart3_txd", "rgmii1_rd2", "mmc0_dat4", "mmc1_dat3", "uart1_rin", "mcasp0_axr1", "gpio2_19"), + _PIN(0x93c, "MII1_RXD1", 84, 7, "gmii1_rxd1", "rmii1_rxd1", "rgmii1_rd1", "mcasp1_axr3", "mcasp1_fsr", "eQEP0_strobe", "mmc2_clk", "gpio2_20"), + _PIN(0x940, "MII1_RXD0", 85, 7, "gmii1_rxd0", "rmii1_rxd0", "rgmii1_rd0", "mcasp1_ahclkx", "mcasp1_ahclkr", "mcasp1_aclkr", "mcasp0_axr3", "gpio2_21"), + _PIN(0x944, "RMII1_REF_CLK", 29, 7, "rmii1_refclk", "xdma_event_intr2", "spi1_cs0", "uart5_txd", "mcasp1_axr3", "mmc0_pow", "mcasp1_ahclkx", "gpio0_29"), + _PIN(0x948, "MDIO", 0, 7, "mdio_data", "timer6", "uart5_rxd", "uart3_ctsn", "mmc0_sdcd","mmc1_cmd", "mmc2_cmd","gpio0_0"), + _PIN(0x94c, "MDC", 1, 7, "mdio_clk", "timer5", "uart5_txd", "uart3_rtsn", "mmc0_sdwp", "mmc1_clk", "mmc2_clk", "gpio0_1"), + _PIN(0x950, "SPI0_SCLK", 2, 7, "spi0_sclk", "uart2_rxd", "I2C2_SDA", "ehrpwm0A", "pr1_uart0_cts_n", "pr1_edio_sof", "EMU2", "gpio0_2"), + _PIN(0x954, "SPI0_D0", 3, 7, "spi0_d0", "uart2_txd", "I2C2_SCL", "ehrpwm0B", "pr1_uart0_rts_n", "pr1_edio_latch_in", "EMU3", "gpio0_3"), + _PIN(0x958, "SPIO_D1", 4, 7, "spi0_d1", "mmc1_sdwp", "I2C1_SDA", "ehrpwm0_tripzone_input", "pr1_uart0_rxd", "pr1_edio_data_in0", "pr1_edio_data_out0", "gpio0_4"), + _PIN(0x95c, "SPI0_CS0", 5, 7, "spi0_cs0", "mmc2_sdwp", "I2C1_SCL", "ehrpwm0_synci", "pr1_uart0_txd", "pr1_edio_data_in1", "pr1_edio_data_out1", "gpio0_5"), + _PIN(0x960, "SPI0_CS1", 6, 7, "spi0_cs1", "uart3_rxd", "eCAP1_in_PWM1_out", "mcc0_pow", "xdm_event_intr2", "mmc0_sdcd", "EMU4", "gpio0_6"), + _PIN(0x964, "ECAP0_IN_PWM0_OUT",7, 7, "eCAP0_in_PWM0_out", "uart3_txd", "spi1_cs1", "pr1_ecap0_ecap_capin_apwm_o", "spi1_sclk", "mmc0_sdwp", "xdma_event_intr2", "gpio0_7"), + _PIN(0x968, "UART0_CTSn", 40, 7, "uart0_ctsn", "uart4_rxd", "dcan1_tx", "I2C1_SDA", "spi1_d0", "timer7", "pr1_edc_sync0_out", "gpio1_8"), + _PIN(0x96c, "UART0_RTSn", 41, 7, "uart0_rtsn", "uart4_txd", "dcan1_rx", "I2C1_SCL", "spi1_d1", "spi1_cs0", "pr1_edc_sync1_out", "gpio1_9"), + _PIN(0x970, "UART0_rxd", 42, 7, "uart0_rxd", "spi1_cs0", "dcan0_tx", "I2C2_SDA", "eCAP2_in_PWM2_out", "pr1_pru1_pru_r30_14", "pr1_pru1_pru_r31_14", "gpio1_10"), + _PIN(0x974, "UART0_txd", 43, 7, "uart0_txd", "spi1_cs1", "dcan0_rx", "I2C2_SCL", "eCAP1_in_PWM1_out", "pr1_pru1_pru_r30_15", "pr1_pru1_pru_r31_15", "gpio1_11"), + _PIN(0x978, "UART1_CTSn", 12, 7, "uart1_ctsn", "timer6_mux1", "dcan0_tx", "I2C2_SDA", "spi1_cs0", "pr1_uart0_cts_n", "pr1_edc_latch0_in", "gpio0_12"), + _PIN(0x97c, "UART1_RTSn", 13, 7, "uart1_rtsn", "timer5_mux1", "dcan0_rx", "I2C2_SCL", "spi1_cs1", "pr1_uart0_rts_n ", "pr1_edc_latch1_in", "gpio0_13"), + _PIN(0x980, "UART1_RXD", 14, 7, "uart1_rxd", "mmc1_sdwp", "dcan1_tx", "I2C1_SDA", NULL, "pr1_uart0_rxd", "pr1_pru1_pru_r31_16", "gpio0_14"), + _PIN(0x984, "UART1_TXD", 15, 7, "uart1_txd", "mmc2_sdwp", "dcan1_rx", "I2C1_SCL", NULL, "pr1_uart0_txd", "pr1_pru0_pru_r31_16", "gpio0_15"), + _PIN(0x988, "I2C0_SDA", 101, 7, "I2C0_SDA", "timer4", "uart2_ctsn", "eCAP2_in_PWM2_out", NULL, NULL, NULL, "gpio3_5"), + _PIN(0x98c, "I2C0_SCL", 102, 7, "I2C0_SCL", "timer7", "uart2_rtsn", "eCAP1_in_PWM1_out", NULL, NULL, NULL, "gpio3_6"), + _PIN(0x990, "MCASP0_ACLKX", 110, 7, "mcasp0_aclkx", "ehrpwm0A", NULL, "spi1_sclk", "mmc0_sdcd", "pr1_pru0_pru_r30_0", "pr1_pru0_pru_r31_0", "gpio3_14"), + _PIN(0x994, "MCASP0_FSX", 111, 7, "mcasp0_fsx", "ehrpwm0B", NULL, "spi1_d0", "mmc1_sdcd", "pr1_pru0_pru_r30_1", "pr1_pru0_pru_r31_1", "gpio3_15"), + _PIN(0x998, "MCASP0_AXR0", 112, 7, "mcasp0_axr0", "ehrpwm0_tripzone_input", NULL, "spi1_d1", "mmc2_sdcd", "pr1_pru0_pru_r30_2", "pr1_pru0_pru_r31_2", "gpio3_16"), + _PIN(0x99c, "MCASP0_AHCLKR", 113, 7, "mcasp0_ahclkr", "ehrpwm0_synci", "mcasp0_axr2", "spi1_cs0", "eCAP2_in_PWM2_out", "pr1_pru0_pru_r30_3", "pr1_pru0_pru_r31_3", "gpio3_17"), + _PIN(0x9a0, "MCASP0_ACLKR", 114, 7, "mcasp0_aclkr", "eQEP0A_in", "mcasp0_axr2", "mcasp1_aclkx", "mmc0_sdwp", "pr1_pru0_pru_r30_4", "pr1_pru0_pru_r31_4", "gpio3_18"), + _PIN(0x9a4, "MCASP0_FSR", 115, 7, "mcasp0_fsr", "eQEP0B_in", "mcasp0_axr3", "mcasp1_fsx", "EMU2", "pr1_pru0_pru_r30_5", "pr1_pru0_pru_r31_5", "gpio3_19"), + _PIN(0x9a8, "MCASP0_AXR1", 116, 7, "mcasp0_axr1", "eQEP0_index", NULL, "mcasp1_axr0", "EMU3", "pr1_pru0_pru_r30_6", "pr1_pru0_pru_r31_6", "gpio3_20"), + _PIN(0x9ac, "MCASP0_AHCLKX", 117, 7, "mcasp0_ahclkx", "eQEP0_strobe", "mcasp0_axr3", "mcasp1_axr1", "EMU4", "pr1_pru0_pru_r30_7", "pr1_pru0_pru_r31_7", "gpio3_21"), + _PIN(0x9b0, "XDMA_EVENT_INTR0", 19, 7, "xdma_event_intr0", NULL, "timer4", "clkout1", "spi1_cs1", "pr1_pru1_pru_r31_16", "EMU2", "gpio0_19"), + _PIN(0x9b4, "XDMA_EVENT_INTR1", 20, 7, "xdma_event_intr1", NULL, "tclkin", "clkout2", "timer7", "pr1_pru0_pru_r31_16", "EMU3", "gpio0_20"), +#if 0 + _PIN(0x9b8, "nresetin_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9bc, "porz", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9c0, "nnmi", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9c4, "osc0_in", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9c8, "osc0_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9cc, "osc0_vss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9d0, "tms", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9d4, "tdi", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9d8, "tdo", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9dc, "tck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9e0, "ntrst", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +#endif + _PIN(0x9e4, "EMU0", 103, 7, "EMU0", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_7"), + _PIN(0x9e8, "EMU1", 104, 0, "EMU1", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_8"), +#if 0 + _PIN(0x9ec, "osc1_in", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9f0, "osc1_out", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9f4, "osc1_vss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9f8, "rtc_porz", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0x9fc, "pmic_power_en", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa00, "ext_wakeup", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa04, "enz_kaldo_1p8v", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +#endif + _PIN(0xa08, "USB0_DM", 0, 0, "USB0_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa0c, "USB0_DP", 0, 0, "USB0_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa10, "USB0_CE", 0, 0, "USB0_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa14, "USB0_ID", 0, 0, "USB0_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa18, "USB0_VBUS", 0, 0, "USB0_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa1c, "USB0_DRVVBUS", 18, 7, "USB0_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio0_18"), + _PIN(0xa20, "USB1_DM", 0, 0, "USB1_DM", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa24, "USB1_DP", 0, 0, "USB1_DP", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa28, "USB1_CE", 0, 0, "USB1_CE", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa2c, "USB1_ID", 0, 0, "USB1_ID", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa30, "USB1_VBUS", 0, 0, "USB1_VBUS", NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa34, "USB1_DRVVBUS", 109, 7, "USB1_DRVVBUS", NULL, NULL, NULL, NULL, NULL, NULL, "gpio3_13"), +#if 0 + _PIN(0xa38, "ddr_resetn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa3c, "ddr_csn0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa40, "ddr_cke", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa44, "ddr_ck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa48, "ddr_nck", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa4c, "ddr_casn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa50, "ddr_rasn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa54, "ddr_wen", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa58, "ddr_ba0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa5c, "ddr_ba1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa60, "ddr_ba2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa64, "ddr_a0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa68, "ddr_a1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa6c, "ddr_a2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa70, "ddr_a3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa74, "ddr_a4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa78, "ddr_a5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa7c, "ddr_a6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa80, "ddr_a7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa84, "ddr_a8", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa88, "ddr_a9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa8c, "ddr_a10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa90, "ddr_a11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa94, "ddr_a12", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa98, "ddr_a13", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xa9c, "ddr_a14", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xaa0, "ddr_a15", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xaa4, "ddr_odt", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xaa8, "ddr_d0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xaac, "ddr_d1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xab0, "ddr_d2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xab4, "ddr_d3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xab8, "ddr_d4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xabc, "ddr_d5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xac0, "ddr_d6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xac4, "ddr_d7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xac8, "ddr_d8", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xacc, "ddr_d9", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xad0, "ddr_d10", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xad4, "ddr_d11", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xad8, "ddr_d12", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xadc, "ddr_d13", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xae0, "ddr_d14", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xae4, "ddr_d15", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xae8, "ddr_dqm0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xaec, "ddr_dqm1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xaf0, "ddr_dqs0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xaf4, "ddr_dqsn0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xaf8, "ddr_dqs1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xafc, "ddr_dqsn1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb00, "ddr_vref", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb04, "ddr_vtp", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb08, "ddr_strben0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb0c, "ddr_strben1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb2c, "ain0", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb28, "ain1", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb24, "ain2", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb20, "ain3", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb1c, "ain4", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb18, "ain5", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb14, "ain6", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb10, "ain7", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb30, "vrefp", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb34, "vrefn", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb38, "avdd", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb3c, "avss", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb40, "iforce", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb44, "vsense", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), + _PIN(0xb48, "testout", 0, 0, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL), +#endif + { .ballname = NULL }, +}; + +const struct sitara_cm_device sitara_cm_dev = { + .padconf_muxmode_mask = 0x7, + .padconf_sate_mask = 0x78, + .padstate = (struct sitara_cm_padstate *) &ti_padstate_devmap, + .padconf = (struct sitara_cm_padconf *) &ti_padconf_devmap, +}; + +int +sitara_cm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags) +{ + unsigned int state = 0; + if (flags & GPIO_PIN_OUTPUT) { + if (flags & GPIO_PIN_PULLUP) + state = PADCONF_OUTPUT_PULLUP; + else + state = PADCONF_OUTPUT; + } else if (flags & GPIO_PIN_INPUT) { + if (flags & GPIO_PIN_PULLUP) + state = PADCONF_INPUT_PULLUP; + else if (flags & GPIO_PIN_PULLDOWN) + state = PADCONF_INPUT_PULLDOWN; + else + state = PADCONF_INPUT; + } + return sitara_cm_padconf_set_gpiomode(gpio, state); +} + +void +sitara_cm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags) +{ + unsigned int state; + if (sitara_cm_padconf_get_gpiomode(gpio, &state) != 0) + *flags = 0; + else { + switch (state) { + case PADCONF_OUTPUT: + *flags = GPIO_PIN_OUTPUT; + break; + case PADCONF_OUTPUT_PULLUP: + *flags = GPIO_PIN_OUTPUT | GPIO_PIN_PULLUP; + break; + case PADCONF_INPUT: + *flags = GPIO_PIN_INPUT; + break; + case PADCONF_INPUT_PULLUP: + *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLUP; + break; + case PADCONF_INPUT_PULLDOWN: + *flags = GPIO_PIN_INPUT | GPIO_PIN_PULLDOWN; + break; + default: + *flags = 0; + break; + } + } +} diff --git a/sys/arch/armv7/omap/am335x_prcmreg.h b/sys/arch/armv7/omap/am335x_prcmreg.h new file mode 100644 index 00000000000..f7077423c15 --- /dev/null +++ b/sys/arch/armv7/omap/am335x_prcmreg.h @@ -0,0 +1,48 @@ +/* $OpenBSD: am335x_prcmreg.h,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* + * Copyright (c) 2013 Raphael Graf <r@undefined.ch> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define AM335X_CLKCTRL_MODULEMODE_ENABLE 2 +#define AM335X_CLKCTRL_MODULEMODE_DISABLE 0 +#define AM335X_CLKCTRL_MODULEMODE_MASK 0x00000003 + +#define PRCM_AM335X_CM_PER 0x0000 +#define PRCM_AM335X_USB0_CLKCTRL 0x001c +#define PRCM_AM335X_MMC0_CLKCTRL 0x003c +#define PRCM_AM335X_TIMER2_CLKCTRL 0x0080 +#define PRCM_AM335X_TIMER3_CLKCTRL 0x0084 +#define PRCM_AM335X_GPIO1_CLKCTRL 0x00ac +#define PRCM_AM335X_GPIO2_CLKCTRL 0x00b0 +#define PRCM_AM335X_GPIO3_CLKCTRL 0x00b4 +#define PRCM_AM335X_CM_WKUP 0x0400 +#define PRCM_AM335X_GPIO0_CLKCTRL 0x0408 +#define PRCM_AM335X_TIMER0_CLKCTRL 0x0410 +#define PRCM_AM335X_CM_DPLL 0x0500 +#define PRCM_AM335X_CLKSEL_TIMER2_CLK 0x0508 +#define PRCM_AM335X_CLKSEL_TIMER3_CLK 0x050c +#define PRCM_AM335X_CM_MPU 0x0600 +#define PRCM_AM335X_CM_DEVICE 0x0700 +#define PRCM_AM335X_CM_RTC 0x0800 +#define PRCM_AM335X_CM_GFX 0x0900 +#define PRCM_AM335X_CM_CEFUSE 0x0a00 +#define PRCM_AM335X_PRM_IRQ 0x0b00 +#define PRCM_AM335X_PRM_PER 0x0c00 +#define PRCM_AM335X_PRM_WKUP 0x0d00 +#define PRCM_AM335X_PRM_MPU 0x0e00 +#define PRCM_AM335X_PRM_DEVICE 0x0f00 +#define PRCM_AM335X_PRM_RTC 0x1000 +#define PRCM_AM335X_PRM_GFX 0x1100 +#define PRCM_AM335X_PRM_CEFUSE 0x1200 diff --git a/sys/arch/armv7/omap/beagle_machdep.c b/sys/arch/armv7/omap/beagle_machdep.c new file mode 100644 index 00000000000..a48d1a62c90 --- /dev/null +++ b/sys/arch/armv7/omap/beagle_machdep.c @@ -0,0 +1,1024 @@ +/* $OpenBSD: beagle_machdep.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* $NetBSD: lubbock_machdep.c,v 1.2 2003/07/15 00:25:06 lukem Exp $ */ + +/* + * Copyright (c) 2002, 2003 Genetec Corporation. All rights reserved. + * Written by Hiroyuki Bessho for Genetec Corporation. + * + * 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. The name of Genetec Corporation may not be used to endorse or + * promote products derived from this software without specific prior + * written permission. + * + * THIS SOFTWARE IS PROVIDED BY GENETEC CORPORATION ``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 GENETEC CORPORATION + * 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. + * + * Machine dependant functions for kernel setup for + * Intel DBPXA250 evaluation board (a.k.a. Lubbock). + * Based on iq80310_machhdep.c + */ +/* + * Copyright (c) 2001 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. + */ + +/* + * Copyright (c) 1997,1998 Mark Brinicombe. + * Copyright (c) 1997,1998 Causality Limited. + * All rights reserved. + * + * 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 by Mark Brinicombe + * for the NetBSD Project. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR OR CONTRIBUTORS 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. + * + * Machine dependant functions for kernel setup for Intel IQ80310 evaluation + * boards using RedBoot firmware. + */ + +/* + * DIP switches: + * + * S19: no-dot: set RB_KDB. enter kgdb session. + * S20: no-dot: set RB_SINGLE. don't go multi user mode. + */ + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/exec.h> +#include <sys/proc.h> +#include <sys/msgbuf.h> +#include <sys/reboot.h> +#include <sys/termios.h> + +#include <uvm/uvm_extern.h> + +#include <sys/conf.h> +#include <sys/queue.h> +#include <sys/device.h> +#include <dev/cons.h> +#include <dev/ic/smc91cxxreg.h> + +#include <machine/db_machdep.h> +#include <ddb/db_sym.h> +#include <ddb/db_extern.h> + +#include <machine/bootconfig.h> +#include <machine/bus.h> +#include <machine/cpu.h> +#include <machine/frame.h> +#include <arm/undefined.h> +#include <arm/machdep.h> + +#include <arm/armv7/armv7reg.h> +#include <arm/armv7/armv7var.h> + +#include <arm/cortex/smc.h> +#include <machine/machine_reg.h> +#include <armv7/omap/omapvar.h> + +#include "wsdisplay.h" + +/* Kernel text starts 2MB in from the bottom of the kernel address space. */ +#define KERNEL_TEXT_BASE (KERNEL_BASE + 0x00000000) +#define KERNEL_VM_BASE (KERNEL_BASE + 0x04000000) + +/* + * The range 0xc1000000 - 0xccffffff is available for kernel VM space + * Core-logic registers and I/O mappings occupy 0xfd000000 - 0xffffffff + */ +/* +#define KERNEL_VM_SIZE 0x0C000000 +*/ +#define KERNEL_VM_SIZE 0x10000000 + + +/* + * Address to call from cpu_reset() to reset the machine. + * This is machine architecture dependant as it varies depending + * on where the ROM appears when you turn the MMU off. + */ + +u_int cpu_reset_address = 0; + +/* Define various stack sizes in pages */ +#define IRQ_STACK_SIZE 1 +#define ABT_STACK_SIZE 1 +#ifdef IPKDB +#define UND_STACK_SIZE 2 +#else +#define UND_STACK_SIZE 1 +#endif + +BootConfig bootconfig; /* Boot config storage */ +char *boot_args = NULL; +char *boot_file = ""; + +vaddr_t physical_start; +vaddr_t physical_freestart; +vaddr_t physical_freeend; +vaddr_t physical_end; +u_int free_pages; +vaddr_t pagetables_start; +int physmem = 0; + +/*int debug_flags;*/ +#ifndef PMAP_STATIC_L1S +int max_processes = 64; /* Default number */ +#endif /* !PMAP_STATIC_L1S */ + +/* Physical and virtual addresses for some global pages */ +pv_addr_t systempage; +pv_addr_t irqstack; +pv_addr_t undstack; +pv_addr_t abtstack; +extern pv_addr_t kernelstack; +pv_addr_t minidataclean; + +vaddr_t msgbufphys; + +extern u_int data_abort_handler_address; +extern u_int prefetch_abort_handler_address; +extern u_int undefined_handler_address; + +#ifdef PMAP_DEBUG +extern int pmap_debug_level; +#endif + +uint32_t board_id; + +#define KERNEL_PT_SYS 0 /* Page table for mapping proc0 zero page */ +#define KERNEL_PT_KERNEL 1 /* Page table for mapping kernel */ +#define KERNEL_PT_KERNEL_NUM 32 +#define KERNEL_PT_VMDATA (KERNEL_PT_KERNEL+KERNEL_PT_KERNEL_NUM) + /* Page tables for mapping kernel VM */ +#define KERNEL_PT_VMDATA_NUM 8 /* start with 16MB of KVM */ +#define NUM_KERNEL_PTS (KERNEL_PT_VMDATA + KERNEL_PT_VMDATA_NUM) + +pv_addr_t kernel_pt_table[NUM_KERNEL_PTS]; + +extern struct user *proc0paddr; + +/* + * safepri is a safe priority for sleep to set for a spin-wait + * during autoconfiguration or after a panic. + */ +int safepri = 0; + +/* Prototypes */ + +void omdog_reset(void); +void beagle_powerdown(void); + +char bootargs[MAX_BOOT_STRING]; +void process_kernel_args(char *); + +void consinit(void); +void early_clkman(u_int, int); +void kgdb_port_init(void); +void change_clock(uint32_t v); + +bs_protos(bs_notimpl); + +#include "com.h" +#if NCOM > 0 +#include <dev/ic/comreg.h> +#include <dev/ic/comvar.h> +#endif + +#ifndef CONSPEED +#define CONSPEED B115200 /* What u-boot */ +#endif +#ifndef CONMODE +#define CONMODE ((TTYDEF_CFLAG & ~(CSIZE | CSTOPB | PARENB)) | CS8) /* 8N1 */ +#endif + +int comcnspeed = CONSPEED; +int comcnmode = CONMODE; + +/* + * + */ +void +beagle_powerdown(void) +{ + + /* + pxa2x0_watchdog_boot(); + */ +} + +/* + * void boot(int howto, char *bootstr) + * + * Reboots the system + * + * Deal with any syncing, unmounting, dumping and shutdown hooks, + * then reset the CPU. + */ +void +boot(int howto) +{ +#ifdef DIAGNOSTIC + /* info */ + printf("boot: howto=%08x curproc=%p\n", howto, curproc); +#endif + + /* + * If we are still cold then hit the air brakes + * and crash to earth fast + */ + if (cold) { + doshutdownhooks(); + if ((howto & (RB_HALT | RB_USERREQ)) != RB_USERREQ) { + printf("The operating system has halted.\n"); + printf("Please press any key to reboot.\n\n"); + cngetc(); + } + printf("rebooting...\n"); + delay(500000); + omdog_reset(); + printf("reboot failed; spinning\n"); + while(1); + /*NOTREACHED*/ + } + + /* Disable console buffering */ +/* cnpollc(1);*/ + + /* + * If RB_NOSYNC was not specified sync the discs. + * Note: Unless cold is set to 1 here, syslogd will die during the + * unmount. It looks like syslogd is getting woken up only to find + * that it cannot page part of the binary in as the filesystem has + * been unmounted. + */ + if (!(howto & RB_NOSYNC)) + bootsync(howto); + + /* Say NO to interrupts */ + splhigh(); + + /* Do a dump if requested. */ + if ((howto & (RB_DUMP | RB_HALT)) == RB_DUMP) + dumpsys(); + + /* Run any shutdown hooks */ + doshutdownhooks(); + + /* Make sure IRQ's are disabled */ + IRQdisable; + + if (howto & RB_HALT) { + if (howto & RB_POWERDOWN) { + + printf("\nAttempting to power down...\n"); + delay(500000); + beagle_powerdown(); + } + + printf("The operating system has halted.\n"); + printf("Please press any key to reboot.\n\n"); + cngetc(); + } + + printf("rebooting...\n"); + delay(500000); + omdog_reset(); + printf("reboot failed; spinning\n"); + while(1); + /*NOTREACHED*/ +} + +static __inline +pd_entry_t * +read_ttb(void) +{ + long ttb; + + __asm __volatile("mrc p15, 0, %0, c2, c0, 0" : "=r" (ttb)); + + + return (pd_entry_t *)(ttb & ~((1<<14)-1)); +} + +#if 1 +#define VERBOSE_INIT_ARM +#endif + +/* + * simple memory mapping function used in early bootstrap stage + * before pmap is initialized. + * size and cacheability are ignored and map one section with nocache. + */ +static vaddr_t section_free = 0xfd000000; /* XXX - huh */ + +int bootstrap_bs_map(void *t, bus_addr_t bpa, bus_size_t size, + int flags, bus_space_handle_t *bshp); +int +bootstrap_bs_map(void *t, bus_addr_t bpa, bus_size_t size, + int flags, bus_space_handle_t *bshp) +{ + u_long startpa; + vaddr_t va; + pd_entry_t *pagedir = read_ttb(); + /* This assumes PA==VA for page directory */ + + va = section_free; + section_free += L1_S_SIZE; + + /* + startpa = trunc_page(bpa); + */ + startpa = bpa & ~L1_S_OFFSET; + pmap_map_section((vaddr_t)pagedir, va, startpa, + VM_PROT_READ | VM_PROT_WRITE, PTE_NOCACHE); + cpu_tlb_flushD(); + + *bshp = (bus_space_handle_t)(va + (bpa - startpa)); + + return(0); +} + +static void +copy_io_area_map(pd_entry_t *new_pd) +{ + pd_entry_t *cur_pd = read_ttb(); + vaddr_t va; + + for (va = MACHINE_IO_AREA_VBASE; + (cur_pd[va>>L1_S_SHIFT] & L1_TYPE_MASK) == L1_TYPE_S; + va += L1_S_SIZE) { + + new_pd[va>>L1_S_SHIFT] = cur_pd[va>>L1_S_SHIFT]; + if (va == (ARM_VECTORS_HIGH & ~(0x00400000 - 1))) + break; /* STUPID */ + + } +} + +void parse_uboot_tags(void *); + +/* + * u_int initarm(...) + * + * Initial entry point on startup. This gets called before main() is + * entered. + * It should be responsible for setting up everything that must be + * in place when main is called. + * This includes + * Taking a copy of the boot configuration structure. + * Initialising the physical console so characters can be printed. + * Setting up page tables for the kernel + * Relocating the kernel to the bottom of physical memory + */ +u_int +initarm(void *arg0, void *arg1, void *arg2) +{ + int loop; + int loop1; + u_int l1pagetable; + pv_addr_t kernel_l1pt; + paddr_t memstart; + psize_t memsize; + extern void omap4_smc_call(uint32_t, uint32_t); + +#if 0 + int led_data = 0; +#endif + /* early bus_space_map support */ + struct bus_space tmp_bs_tag; + int (*map_func_save)(void *, bus_addr_t, bus_size_t, int, + bus_space_handle_t *); + + board_id = (uint32_t)arg1; + + /* + * Heads up ... Setup the CPU / MMU / TLB functions + */ + if (set_cpufuncs()) + panic("cpu not recognized!"); + + switch (board_id) { + case BOARD_ID_OMAP4_PANDA: + /* disable external L2 cache */ + omap4_smc_call(0x102, 0); + break; + } + +#if 0 + /* Calibrate the delay loop. */ +#endif + + /* + * Temporarily replace bus_space_map() functions so that + * console devices can get mapped. + * + * Note that this relies upon the fact that both regular + * and a4x bus_space tags use the same map function. + */ +#if defined(CPU_ARMv7) + tmp_bs_tag = armv7_bs_tag; + map_func_save = armv7_bs_tag.bs_map; + armv7_bs_tag.bs_map = bootstrap_bs_map; + armv7_a4x_bs_tag.bs_map = bootstrap_bs_map; +#endif + tmp_bs_tag.bs_map = bootstrap_bs_map; + + /* setup a serial console for very early boot */ + consinit(); + + /* Talk to the user */ + printf("\nOpenBSD/beagle booting ...\n"); + + printf("arg0 %p arg1 %p arg2 %p\n", arg0, arg1, arg2); + parse_uboot_tags(arg2); + + /* + * Examine the boot args string for options we need to know about + * now. + */ + process_kernel_args(bootconfig.bootstring); +#ifdef RAMDISK_HOOKS + boothowto |= RB_DFLTROOT; +#endif /* RAMDISK_HOOKS */ + + + /* normally u-boot will set up bootconfig.dramblocks */ + if (bootconfig.dramblocks == 0) { + uint32_t sdrc_mcfg_0, sdrc_mcfg_1, memsize0, memsize1; + sdrc_mcfg_0 = *(uint32_t *)0x6d000080; + sdrc_mcfg_1 = *(uint32_t *)0x6d0000b0; + memsize0 = (((sdrc_mcfg_0 >> 8))&0x3ff) * (2 * 1024 * 1024); + memsize1 = (((sdrc_mcfg_1 >> 8))&0x3ff) * (2 * 1024 * 1024); + memsize = memsize0 + memsize1; + + memstart = SDRAM_START; + memsize = 0x02000000; /* 32MB */ + /* Fake bootconfig structure for the benefit of pmap.c */ + /* XXX must make the memory description h/w independant */ + bootconfig.dram[0].address = memstart; + bootconfig.dram[0].pages = memsize0 / PAGE_SIZE; + bootconfig.dramblocks = 1; + if (memsize1 != 0) { + bootconfig.dram[1].address = bootconfig.dram[0].address + + memsize0; /* XXX */ + bootconfig.dram[1].pages = memsize1 / PAGE_SIZE; + bootconfig.dramblocks++; /* both banks populated */ + } + } else { + /* doesn't deal with multiple segments, hopefully u-boot collaped them into one */ + memstart = bootconfig.dram[0].address; + memsize = bootconfig.dram[0].pages * PAGE_SIZE; + printf("memory size derived from u-boot\n"); + for (loop = 0; loop < bootconfig.dramblocks; loop++) { + printf("bootconf.mem[%d].address = %08x pages %d/0x%08x\n", + loop, bootconfig.dram[0].address, bootconfig.dram[0].pages, + bootconfig.dram[0].pages * PAGE_SIZE); + } + } + + /* + * Set up the variables that define the availablilty of + * physical memory. For now, we're going to set + * physical_freestart to 0xa0200000 (where the kernel + * was loaded), and allocate the memory we need downwards. + * If we get too close to the page tables that RedBoot + * set up, we will panic. We will update physical_freestart + * and physical_freeend later to reflect what pmap_bootstrap() + * wants to see. + * + * XXX pmap_bootstrap() needs an enema. + */ + physical_start = bootconfig.dram[0].address; + physical_end = physical_start + (bootconfig.dram[0].pages * PAGE_SIZE); + + { + extern char _end[]; + physical_freestart = (((unsigned long)_end - KERNEL_TEXT_BASE +0xfff) & ~0xfff) + memstart; + physical_freeend = memstart+memsize; + } + + physmem = (physical_end - physical_start) / PAGE_SIZE; + +#ifdef DEBUG + /* Tell the user about the memory */ + printf("physmemory: %d pages at 0x%08lx -> 0x%08lx\n", physmem, + physical_start, physical_end - 1); +#endif + + /* + * Okay, the kernel starts 2MB in from the bottom of physical + * memory. We are going to allocate our bootstrap pages downwards + * from there. + * + * We need to allocate some fixed page tables to get the kernel + * going. We allocate one page directory and a number of page + * tables and store the physical addresses in the kernel_pt_table + * array. + * + * The kernel page directory must be on a 16K boundary. The page + * tables must be on 4K bounaries. What we do is allocate the + * page directory on the first 16K boundary that we encounter, and + * the page tables on 4K boundaries otherwise. Since we allocate + * at least 3 L2 page tables, we are guaranteed to encounter at + * least one 16K aligned region. + */ + +#ifdef VERBOSE_INIT_ARM + printf("Allocating page tables\n"); +#endif + + free_pages = (physical_freeend - physical_freestart) / PAGE_SIZE; + +#ifdef VERBOSE_INIT_ARM + printf("freestart = 0x%08lx, free_pages = %d (0x%08x)\n", + physical_freestart, free_pages, free_pages); +#endif + + /* Define a macro to simplify memory allocation */ +#define valloc_pages(var, np) \ + alloc_pages((var).pv_pa, (np)); \ + (var).pv_va = KERNEL_BASE + (var).pv_pa - physical_start; + +#define alloc_pages(var, np) \ + (var) = physical_freestart ; \ + physical_freestart += ((np) * PAGE_SIZE); \ + if (physical_freeend < physical_freestart) \ + panic("initarm: out of memory"); \ + free_pages -= (np); \ + memset((char *)(var), 0, ((np) * PAGE_SIZE)); + + loop1 = 0; + kernel_l1pt.pv_pa = 0; + for (loop = 0; loop <= NUM_KERNEL_PTS; ++loop) { + /* Are we 16KB aligned for an L1 ? */ + if (((physical_freestart) & (L1_TABLE_SIZE - 1)) == 0 + && kernel_l1pt.pv_pa == 0) { + valloc_pages(kernel_l1pt, L1_TABLE_SIZE / PAGE_SIZE); + } else { + valloc_pages(kernel_pt_table[loop1], + L2_TABLE_SIZE / PAGE_SIZE); + ++loop1; + } + } + + /* This should never be able to happen but better confirm that. */ + if (!kernel_l1pt.pv_pa || (kernel_l1pt.pv_pa & (L1_TABLE_SIZE-1)) != 0) + panic("initarm: Failed to align the kernel page directory"); + + /* + * Allocate a page for the system page mapped to V0x00000000 + * This page will just contain the system vectors and can be + * shared by all processes. + */ + vector_page = ARM_VECTORS_HIGH; + alloc_pages(systempage.pv_pa, 1); + systempage.pv_va = vector_page; + + /* Allocate stacks for all modes */ + valloc_pages(irqstack, IRQ_STACK_SIZE); + valloc_pages(abtstack, ABT_STACK_SIZE); + valloc_pages(undstack, UND_STACK_SIZE); + valloc_pages(kernelstack, UPAGES); + + /* Allocate enough pages for cleaning the Mini-Data cache. */ + +#ifdef VERBOSE_INIT_ARM + printf("IRQ stack: p0x%08lx v0x%08lx\n", irqstack.pv_pa, + irqstack.pv_va); + printf("ABT stack: p0x%08lx v0x%08lx\n", abtstack.pv_pa, + abtstack.pv_va); + printf("UND stack: p0x%08lx v0x%08lx\n", undstack.pv_pa, + undstack.pv_va); + printf("SVC stack: p0x%08lx v0x%08lx\n", kernelstack.pv_pa, + kernelstack.pv_va); +#endif + + /* + * XXX Defer this to later so that we can reclaim the memory + * XXX used by the RedBoot page tables. + */ + alloc_pages(msgbufphys, round_page(MSGBUFSIZE) / PAGE_SIZE); + + /* + * Ok we have allocated physical pages for the primary kernel + * page tables + */ + +#ifdef VERBOSE_INIT_ARM + printf("Creating L1 page table at 0x%08lx\n", kernel_l1pt.pv_pa); +#endif + + /* + * Now we start construction of the L1 page table + * We start by mapping the L2 page tables into the L1. + * This means that we can replace L1 mappings later on if necessary + */ + l1pagetable = kernel_l1pt.pv_pa; + + /* Map the L2 pages tables in the L1 page table */ + pmap_link_l2pt(l1pagetable, vector_page & ~(0x00400000 - 1), + &kernel_pt_table[KERNEL_PT_SYS]); + + for (loop = 0; loop < KERNEL_PT_KERNEL_NUM; loop++) + pmap_link_l2pt(l1pagetable, KERNEL_BASE + loop * 0x00400000, + &kernel_pt_table[KERNEL_PT_KERNEL + loop]); + + for (loop = 0; loop < KERNEL_PT_VMDATA_NUM; loop++) + pmap_link_l2pt(l1pagetable, KERNEL_VM_BASE + loop * 0x00400000, + &kernel_pt_table[KERNEL_PT_VMDATA + loop]); + + /* update the top of the kernel VM */ + pmap_curmaxkvaddr = + KERNEL_VM_BASE + (KERNEL_PT_VMDATA_NUM * 0x00400000); + +#ifdef VERBOSE_INIT_ARM + printf("Mapping kernel\n"); +#endif + + /* Now we fill in the L2 pagetable for the kernel static code/data */ + { + extern char etext[], _end[]; + size_t textsize = (u_int32_t) etext - KERNEL_TEXT_BASE; + size_t totalsize = (u_int32_t) _end - KERNEL_TEXT_BASE; + u_int logical; + + textsize = (textsize + PGOFSET) & ~PGOFSET; + totalsize = (totalsize + PGOFSET) & ~PGOFSET; + + logical = 0x00000000; /* offset of kernel in RAM */ + + logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, + physical_start + logical, textsize, + VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE); + logical += pmap_map_chunk(l1pagetable, KERNEL_BASE + logical, + physical_start + logical, totalsize - textsize, + VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + } + +#ifdef VERBOSE_INIT_ARM + printf("Constructing L2 page tables\n"); +#endif + + /* Map the stack pages */ + pmap_map_chunk(l1pagetable, irqstack.pv_va, irqstack.pv_pa, + IRQ_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + pmap_map_chunk(l1pagetable, abtstack.pv_va, abtstack.pv_pa, + ABT_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + pmap_map_chunk(l1pagetable, undstack.pv_va, undstack.pv_pa, + UND_STACK_SIZE * PAGE_SIZE, VM_PROT_READ|VM_PROT_WRITE, PTE_CACHE); + pmap_map_chunk(l1pagetable, kernelstack.pv_va, kernelstack.pv_pa, + UPAGES * PAGE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_CACHE); + + pmap_map_chunk(l1pagetable, kernel_l1pt.pv_va, kernel_l1pt.pv_pa, + L1_TABLE_SIZE, VM_PROT_READ | VM_PROT_WRITE, PTE_PAGETABLE); + + for (loop = 0; loop < NUM_KERNEL_PTS; ++loop) { + pmap_map_chunk(l1pagetable, kernel_pt_table[loop].pv_va, + kernel_pt_table[loop].pv_pa, L2_TABLE_SIZE, + VM_PROT_READ|VM_PROT_WRITE, PTE_PAGETABLE); + } + + /* Map the Mini-Data cache clean area. */ + + /* Map the vector page. */ +#if 0 + /* MULTI-ICE requires that page 0 is NC/NB so that it can download the + * cache-clean code there. */ + pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa, + VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_NOCACHE); +#else + pmap_map_entry(l1pagetable, vector_page, systempage.pv_pa, + VM_PROT_READ|VM_PROT_WRITE|VM_PROT_EXECUTE, PTE_CACHE); +#endif + + /* + * map integrated peripherals at same address in l1pagetable + * so that we can continue to use console. + */ + copy_io_area_map((pd_entry_t *)l1pagetable); + + + /* + * Now we have the real page tables in place so we can switch to them. + * Once this is done we will be running with the REAL kernel page + * tables. + */ + + /* be a client to all domains */ + cpu_domains(0x55555555); + /* Switch tables */ + + cpu_domains((DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)) | DOMAIN_CLIENT); + setttb(kernel_l1pt.pv_pa); + cpu_tlb_flushID(); + cpu_domains(DOMAIN_CLIENT << (PMAP_DOMAIN_KERNEL*2)); + + /* + * Moved from cpu_startup() as data_abort_handler() references + * this during uvm init + */ + proc0paddr = (struct user *)kernelstack.pv_va; + proc0.p_addr = proc0paddr; + + arm32_vector_init(vector_page, ARM_VEC_ALL); + + /* + * Pages were allocated during the secondary bootstrap for the + * stacks for different CPU modes. + * We must now set the r13 registers in the different CPU modes to + * point to these stacks. + * Since the ARM stacks use STMFD etc. we must set r13 to the top end + * of the stack memory. + */ + + set_stackptr(PSR_IRQ32_MODE, + irqstack.pv_va + IRQ_STACK_SIZE * PAGE_SIZE); + set_stackptr(PSR_ABT32_MODE, + abtstack.pv_va + ABT_STACK_SIZE * PAGE_SIZE); + set_stackptr(PSR_UND32_MODE, + undstack.pv_va + UND_STACK_SIZE * PAGE_SIZE); + + /* + * Well we should set a data abort handler. + * Once things get going this will change as we will need a proper + * handler. + * Until then we will use a handler that just panics but tells us + * why. + * Initialisation of the vectors will just panic on a data abort. + * This just fills in a slighly better one. + */ + + data_abort_handler_address = (u_int)data_abort_handler; + prefetch_abort_handler_address = (u_int)prefetch_abort_handler; + undefined_handler_address = (u_int)undefinedinstruction_bounce; + + /* Initialise the undefined instruction handlers */ +#ifdef VERBOSE_INIT_ARM + printf("undefined "); +#endif + undefined_init(); + + /* Load memory into UVM. */ +#ifdef VERBOSE_INIT_ARM + printf("page "); +#endif + uvm_setpagesize(); /* initialize PAGE_SIZE-dependent variables */ + uvm_page_physload(atop(physical_freestart), atop(physical_freeend), + atop(physical_freestart), atop(physical_freeend), 0); + + /* Boot strap pmap telling it where the kernel page table is */ +#ifdef VERBOSE_INIT_ARM + printf("pmap "); +#endif + pmap_bootstrap((pd_entry_t *)kernel_l1pt.pv_va, KERNEL_VM_BASE, + KERNEL_VM_BASE + KERNEL_VM_SIZE); + +#ifdef IPKDB + /* Initialise ipkdb */ + ipkdb_init(); + if (boothowto & RB_KDB) + ipkdb_connect(0); +#endif + + /* + * Restore proper bus_space operation, now that pmap is initialized. + */ +#if defined(CPU_ARMv7) + armv7_bs_tag.bs_map = map_func_save; + armv7_a4x_bs_tag.bs_map = map_func_save; +#endif + +#ifdef DDB + db_machine_init(); + + /* Firmware doesn't load symbols. */ + ddb_init(); + + if (boothowto & RB_KDB) + Debugger(); +#endif + + switch (board_id) { + case BOARD_ID_OMAP3_BEAGLE: + printf("board type: beagle\n"); + break; + case BOARD_ID_AM335X_BEAGLEBONE: + printf("board type: beaglebone\n"); + break; + case BOARD_ID_OMAP3_OVERO: + printf("board type: overo\n"); + break; + case BOARD_ID_OMAP4_PANDA: + printf("board type: panda\n"); + break; + default: + printf("board type %x unknown", board_id); + } + + /* We return the new stack pointer address */ + return(kernelstack.pv_va + USPACE_SVC_STACK_TOP); +} + + +void +process_kernel_args(char *args) +{ + char *cp = args; + + if (cp == NULL) { + boothowto = RB_AUTOBOOT; + return; + } + + boothowto = 0; + + /* Make a local copy of the bootargs */ + strncpy(bootargs, cp, MAX_BOOT_STRING - sizeof(int)); + + cp = bootargs; + boot_file = bootargs; + + /* Skip the kernel image filename */ + while (*cp != ' ' && *cp != 0) + ++cp; + + if (*cp != 0) + *cp++ = 0; + + while (*cp == ' ') + ++cp; + + boot_args = cp; + + printf("bootfile: %s\n", boot_file); + printf("bootargs: %s\n", boot_args); + + /* Setup pointer to boot flags */ + while (*cp != '-') + if (*cp++ == '\0') + return; + + for (;*++cp;) { + int fl; + + fl = 0; + switch(*cp) { + case 'a': + fl |= RB_ASKNAME; + break; + case 'c': + fl |= RB_CONFIG; + break; + case 'd': + fl |= RB_KDB; + break; + case 's': + fl |= RB_SINGLE; + break; + default: + printf("unknown option `%c'\n", *cp); + break; + } + boothowto |= fl; + } +} + + +void +consinit(void) +{ + static int consinit_called = 0; +#if NCOM > 0 + paddr_t paddr; +#endif + + if (consinit_called != 0) + return; + + consinit_called = 1; + +#if NCOM > 0 + switch (board_id) { + case BOARD_ID_OMAP3_BEAGLE: + case BOARD_ID_OMAP3_OVERO: + paddr = 0x49020000; + break; + case BOARD_ID_AM335X_BEAGLEBONE: + paddr = 0x44E09000; /* UART0 */ + break; + case BOARD_ID_OMAP4_PANDA: + paddr = 0x48020000; + break; + default: + panic("board type %x unknown", board_id); + /* XXX - HELP */ + } + comcnattach(&armv7_a4x_bs_tag, paddr, comcnspeed, 48000000, comcnmode); + comdefaultrate = comcnspeed; +#endif /* NCOM */ +} + + +//int glass_console = 0; + +void +board_startup(void) +{ + if (boothowto & RB_CONFIG) { +#ifdef BOOT_CONFIG + user_config(); +#else + printf("kernel does not support -c; continuing..\n"); +#endif + } +} + +void +platform_smc_write(bus_space_tag_t iot, bus_space_handle_t ioh, bus_size_t off, + uint32_t op, uint32_t val) +{ + extern void omap4_smc_call(uint32_t, uint32_t); + + switch (op) { + case 0x100: /* PL310 DEBUG */ + case 0x102: /* PL310 CTL */ + break; + default: + panic("platform_smc_write: invalid operation %d", op); + } + + omap4_smc_call(op, val); +} diff --git a/sys/arch/armv7/omap/dmtimer.c b/sys/arch/armv7/omap/dmtimer.c new file mode 100644 index 00000000000..36c82c9dbd4 --- /dev/null +++ b/sys/arch/armv7/omap/dmtimer.c @@ -0,0 +1,414 @@ +/* + * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> + * Copyright (c) 2013 Raphael Graf <r@undefined.ch> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * WARNING - this timer initializion has not been checked + * to see if it will do _ANYTHING_ sane if the omap enters + * low power mode. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/time.h> +#include <sys/evcount.h> +#include <sys/device.h> +#include <sys/timetc.h> +#include <dev/clock_subr.h> +#include <machine/bus.h> +#include <armv7/omap/omapvar.h> +#include <armv7/omap/prcmvar.h> + +#include <machine/intr.h> +#include <arm/cpufunc.h> + +/* registers */ +#define DM_TIDR 0x000 +#define DM_TIDR_MAJOR 0x00000700 +#define DM_TIDR_MINOR 0x0000003f +#define DM_TIOCP_CFG 0x010 +#define DM_TIOCP_CFG_IDLEMODE (3<<2) +#define DM_TIOCP_CFG_EMUFREE (1<<1) +#define DM_TIOCP_CFG_SOFTRESET (1<<0) +#define DM_TISR 0x028 +#define DM_TISR_TCAR (1<<2) +#define DM_TISR_OVF (1<<1) +#define DM_TISR_MAT (1<<0) +#define DM_TIER 0x2c +#define DM_TIER_TCAR_EN (1<<2) +#define DM_TIER_OVF_EN (1<<1) +#define DM_TIER_MAT_EN (1<<0) +#define DM_TIECR 0x30 +#define DM_TIECR_TCAR_EN (1<<2) +#define DM_TIECR_OVF_EN (1<<1) +#define DM_TIECR_MAT_EN (1<<0) +#define DM_TWER 0x034 +#define DM_TWER_TCAR_EN (1<<2) +#define DM_TWER_OVF_EN (1<<1) +#define DM_TWER_MAT_EN (1<<0) +#define DM_TCLR 0x038 +#define DM_TCLR_GPO (1<<14) +#define DM_TCLR_CAPT (1<<13) +#define DM_TCLR_PT (1<<12) +#define DM_TCLR_TRG (3<<10) +#define DM_TCLR_TRG_O (1<<10) +#define DM_TCLR_TRG_OM (2<<10) +#define DM_TCLR_TCM (3<<8) +#define DM_TCLR_TCM_RISE (1<<8) +#define DM_TCLR_TCM_FALL (2<<8) +#define DM_TCLR_TCM_BOTH (3<<8) +#define DM_TCLR_SCPWM (1<<7) +#define DM_TCLR_CE (1<<6) +#define DM_TCLR_PRE (1<<5) +#define DM_TCLR_PTV (7<<2) +#define DM_TCLR_AR (1<<1) +#define DM_TCLR_ST (1<<0) +#define DM_TCRR 0x03c +#define DM_TLDR 0x040 +#define DM_TTGR 0x044 +#define DM_TWPS 0x048 +#define DM_TWPS_TMAR (1<<4) +#define DM_TWPS_TTGR (1<<3) +#define DM_TWPS_TLDR (1<<2) +#define DM_TWPS_TCLR (1<<0) +#define DM_TWPS_TCRR (1<<1) +#define DM_TWPS_ALL 0x1f +#define DM_TMAR 0x04c +#define DM_TCAR 0x050 +#define DM_TSICR 0x054 +#define DM_TSICR_POSTED (1<<2) +#define DM_TSICR_SFT (1<<1) +#define DM_TCAR2 0x058 + +#define TIMER_FREQUENCY 32768 /* 32kHz is used, selectable */ +#define MAX_TIMERS 2 + +static struct evcount clk_count; +static struct evcount stat_count; + +void dmtimer_attach(struct device *parent, struct device *self, void *args); +int dmtimer_intr(void *frame); +void dmtimer_wait(int reg); +void dmtimer_cpu_initclocks(void); +void dmtimer_delay(u_int); +void dmtimer_setstatclockrate(int newhz); + +u_int dmtimer_get_timecount(struct timecounter *); + +static struct timecounter dmtimer_timecounter = { + dmtimer_get_timecount, NULL, 0xffffffff, 0, "dmtimer", 0, NULL +}; + +bus_space_handle_t dmtimer_ioh0; +int dmtimer_irq = 0; + +struct dmtimer_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh[MAX_TIMERS]; + u_int32_t sc_irq; + u_int32_t sc_ticks_per_second; + u_int32_t sc_ticks_per_intr; + u_int32_t sc_ticks_err_cnt; + u_int32_t sc_ticks_err_sum; + u_int32_t sc_statvar; + u_int32_t sc_statmin; + u_int32_t sc_nexttickevent; + u_int32_t sc_nextstatevent; +}; + +struct cfattach dmtimer_ca = { + sizeof (struct dmtimer_softc), NULL, dmtimer_attach +}; + +struct cfdriver dmtimer_cd = { + NULL, "dmtimer", DV_DULL +}; + +void +dmtimer_attach(struct device *parent, struct device *self, void *args) +{ + struct dmtimer_softc *sc = (struct dmtimer_softc *)self; + struct omap_attach_args *oa = args; + bus_space_handle_t ioh; + u_int32_t rev, cfg; + + sc->sc_iot = oa->oa_iot; + + if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &ioh)) + panic("%s: bus_space_map failed!\n", __func__); + + + prcm_setclock(1, PRCM_CLK_SPEED_32); + prcm_setclock(2, PRCM_CLK_SPEED_32); + prcm_enablemodule(PRCM_TIMER2); + prcm_enablemodule(PRCM_TIMER3); + + /* reset */ + bus_space_write_4(sc->sc_iot, ioh, DM_TIOCP_CFG, + DM_TIOCP_CFG_SOFTRESET); + while (bus_space_read_4(sc->sc_iot, ioh, DM_TIOCP_CFG) + & DM_TIOCP_CFG_SOFTRESET) + ; + + if (self->dv_unit == 0) { + dmtimer_ioh0 = ioh; + dmtimer_irq = oa->oa_dev->irq[0]; + /* enable write posted mode */ + bus_space_write_4(sc->sc_iot, ioh, DM_TSICR, DM_TSICR_POSTED); + /* stop timer */ + bus_space_write_4(sc->sc_iot, ioh, DM_TCLR, 0); + } else if (self->dv_unit == 1) { + /* start timer because it is used in delay */ + /* interrupts and posted mode are disabled */ + sc->sc_irq = dmtimer_irq; + sc->sc_ioh[0] = dmtimer_ioh0; + sc->sc_ioh[1] = ioh; + + bus_space_write_4(sc->sc_iot, ioh, DM_TCRR, 0); + bus_space_write_4(sc->sc_iot, ioh, DM_TLDR, 0); + bus_space_write_4(sc->sc_iot, ioh, DM_TCLR, + DM_TCLR_AR | DM_TCLR_ST); + + dmtimer_timecounter.tc_frequency = TIMER_FREQUENCY; + dmtimer_timecounter.tc_priv = sc; + tc_init(&dmtimer_timecounter); + arm_clock_register(dmtimer_cpu_initclocks, dmtimer_delay, + dmtimer_setstatclockrate, NULL); + } + else + panic("attaching too many dmtimers at 0x%x", + oa->oa_dev->mem[0].addr); + + /* set IDLEMODE to smart-idle */ + cfg = bus_space_read_4(sc->sc_iot, ioh, DM_TIOCP_CFG); + bus_space_write_4(sc->sc_iot, ioh, DM_TIOCP_CFG, + (cfg & ~DM_TIOCP_CFG_IDLEMODE) | 0x02); + + rev = bus_space_read_4(sc->sc_iot, ioh, DM_TIDR); + printf(" rev %d.%d\n", (rev & DM_TIDR_MAJOR) >> 8, rev & DM_TIDR_MINOR); +} + +/* + * See comment in arm/xscale/i80321_clock.c + * + * Counter is count up, but with autoreload timers it is not possible + * to detect how many interrupts passed while interrupts were blocked. + * Also it is not possible to atomically add to the register. + * + * To work around this two timers are used, one is used as a reference + * clock without reload, however we just disable the interrupt it + * could generate. + * + * Internally this keeps track of when the next timer should fire + * and based on that time and the current value of the reference + * clock a number is written into the timer count register to schedule + * the next event. + */ + +int +dmtimer_intr(void *frame) +{ + struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; + u_int32_t now, r, nextevent; + int32_t duration; + + now = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); + + while ((int32_t) (sc->sc_nexttickevent - now) <= 0) { + sc->sc_nexttickevent += sc->sc_ticks_per_intr; + sc->sc_ticks_err_sum += sc->sc_ticks_err_cnt; + + while (sc->sc_ticks_err_sum > hz) { + sc->sc_nexttickevent += 1; + sc->sc_ticks_err_sum -= hz; + } + + clk_count.ec_count++; + hardclock(frame); + } + + while ((int32_t) (sc->sc_nextstatevent - now) <= 0) { + do { + r = random() & (sc->sc_statvar - 1); + } while (r == 0); /* random == 0 not allowed */ + sc->sc_nextstatevent += sc->sc_statmin + r; + stat_count.ec_count++; + statclock(frame); + } + if ((now - sc->sc_nexttickevent) < (now - sc->sc_nextstatevent)) + nextevent = sc->sc_nexttickevent; + else + nextevent = sc->sc_nextstatevent; + + duration = nextevent - + bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); + + if (duration <= 0) { + printf("%s: negative duration!\n", __func__); + duration = 1; /* trigger immediately. */ + } + + if (duration > sc->sc_ticks_per_intr + 1) { + printf("%s: time lost!\n", __func__); + /* + * If interrupts are blocked too long, like during + * the root prompt or ddb, the timer can roll over, + * this will allow the system to continue to run + * even if time is lost. + */ + duration = sc->sc_ticks_per_intr; + sc->sc_nexttickevent = now; + sc->sc_nextstatevent = now; + } + + bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR, + bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR)); + bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCRR, -duration); + dmtimer_wait(DM_TWPS_ALL); + + return 1; +} + +/* + * would be interesting to play with trigger mode while having one timer + * in 32KHz mode, and the other timer running in sysclk mode and use + * the high resolution speeds (matters more for delay than tick timer + */ + +void +dmtimer_cpu_initclocks() +{ + struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; + + stathz = 128; + profhz = 1024; + + sc->sc_ticks_per_second = TIMER_FREQUENCY; /* 32768 */ + + setstatclockrate(stathz); + + sc->sc_ticks_per_intr = sc->sc_ticks_per_second / hz; + sc->sc_ticks_err_cnt = sc->sc_ticks_per_second % hz; + sc->sc_ticks_err_sum = 0; + + /* establish interrupts */ + arm_intr_establish(sc->sc_irq, IPL_CLOCK, dmtimer_intr, + NULL, "tick"); + + /* setup timer 0 */ + + bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TLDR, 0); + + sc->sc_nexttickevent = sc->sc_nextstatevent = bus_space_read_4(sc->sc_iot, + sc->sc_ioh[1], DM_TCRR) + sc->sc_ticks_per_intr; + + bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TIER, DM_TIER_OVF_EN); + bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TWER, DM_TWER_OVF_EN); + bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR, /*clear interrupt flags */ + bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TISR)); + bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCRR, -sc->sc_ticks_per_intr); + dmtimer_wait(DM_TWPS_ALL); + bus_space_write_4(sc->sc_iot, sc->sc_ioh[0], DM_TCLR, /* autoreload and start */ + DM_TCLR_AR | DM_TCLR_ST); + dmtimer_wait(DM_TWPS_ALL); +} + +void +dmtimer_wait(int reg) +{ + struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; + while (bus_space_read_4(sc->sc_iot, sc->sc_ioh[0], DM_TWPS) & reg) + ; +} + +void +dmtimer_delay(u_int usecs) +{ + struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; + u_int32_t clock, oclock, delta, delaycnt; + volatile int j; + int csec, usec; + + if (usecs > (0x80000000 / (TIMER_FREQUENCY))) { + csec = usecs / 10000; + usec = usecs % 10000; + + delaycnt = (TIMER_FREQUENCY / 100) * csec + + (TIMER_FREQUENCY / 100) * usec / 10000; + } else { + delaycnt = TIMER_FREQUENCY * usecs / 1000000; + } + if (delaycnt <= 1) + for (j = 100; j > 0; j--) + ; + + if (sc->sc_ioh[1] == 0) { + /* BAH */ + for (; usecs > 0; usecs--) + for (j = 100; j > 0; j--) + ; + return; + } + oclock = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); + while (1) { + for (j = 100; j > 0; j--) + ; + clock = bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); + delta = clock - oclock; + if (delta > delaycnt) + break; + } + +} + +void +dmtimer_setstatclockrate(int newhz) +{ + struct dmtimer_softc *sc = dmtimer_cd.cd_devs[1]; + int minint, statint; + int s; + + s = splclock(); + + statint = sc->sc_ticks_per_second / newhz; + /* calculate largest 2^n which is smaller than just over half statint */ + sc->sc_statvar = 0x40000000; /* really big power of two */ + minint = statint / 2 + 100; + while (sc->sc_statvar > minint) + sc->sc_statvar >>= 1; + + sc->sc_statmin = statint - (sc->sc_statvar >> 1); + + splx(s); + + /* + * XXX this allows the next stat timer to occur then it switches + * to the new frequency. Rather than switching instantly. + */ +} + + +u_int +dmtimer_get_timecount(struct timecounter *tc) +{ + struct dmtimer_softc *sc = dmtimer_timecounter.tc_priv; + + return bus_space_read_4(sc->sc_iot, sc->sc_ioh[1], DM_TCRR); +} diff --git a/sys/arch/armv7/omap/gptimer.c b/sys/arch/armv7/omap/gptimer.c new file mode 100644 index 00000000000..6741766e4f8 --- /dev/null +++ b/sys/arch/armv7/omap/gptimer.c @@ -0,0 +1,441 @@ +/* $OpenBSD: gptimer.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* + * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* + * WARNING - this timer initializion has not been checked + * to see if it will do _ANYTHING_ sane if the omap enters + * low power mode. + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/time.h> +#include <sys/evcount.h> +#include <sys/device.h> +#include <sys/timetc.h> +#include <dev/clock_subr.h> +#include <machine/bus.h> +#include <armv7/omap/omapvar.h> +#include <armv7/omap/prcmvar.h> + +#include <machine/intr.h> +#include <arm/cpufunc.h> + +/* registers */ +#define GP_TIDR 0x000 +#define GP_TIDR_REV 0xff +#define GP_TIOCP_CFG 0x010 +#define GP_TIOCP_CFG_CLKA 0x000000300 +#define GP_TIOCP_CFG_EMUFREE 0x000000020 +#define GP_TIOCP_CFG_IDLEMODE 0x000000018 +#define GP_TIOCP_CFG_ENAPWAKEUP 0x000000004 +#define GP_TIOCP_CFG_SOFTRESET 0x000000002 +#define GP_TIOCP_CFG_AUTOIDLE 0x000000001 +#define GP_TISTAT 0x014 +#define GP_TISTAT_RESETDONE 0x000000001 +#define GP_TISR 0x018 +#define GP_TISTAT_TCAR 0x00000004 +#define GP_TISTAT_OVF 0x00000002 +#define GP_TISTAT_MATCH 0x00000001 +#define GP_TIER 0x1c +#define GP_TIER_TCAR_EN 0x4 +#define GP_TIER_OVF_EN 0x2 +#define GP_TIER_MAT_EN 0x1 +#define GP_TWER 0x020 +#define GP_TWER_TCAR_EN 0x00000004 +#define GP_TWER_OVF_EN 0x00000002 +#define GP_TWER_MAT_EN 0x00000001 +#define GP_TCLR 0x024 +#define GP_TCLR_GPO (1<<14) +#define GP_TCLR_CAPT (1<<13) +#define GP_TCLR_PT (1<<12) +#define GP_TCLR_TRG (3<<10) +#define GP_TCLR_TRG_O (1<<10) +#define GP_TCLR_TRG_OM (2<<10) +#define GP_TCLR_TCM (3<<8) +#define GP_TCLR_TCM_RISE (1<<8) +#define GP_TCLR_TCM_FALL (2<<8) +#define GP_TCLR_TCM_BOTH (3<<8) +#define GP_TCLR_SCPWM (1<<7) +#define GP_TCLR_CE (1<<6) +#define GP_TCLR_PRE (1<<5) +#define GP_TCLR_PTV (7<<2) +#define GP_TCLR_AR (1<<1) +#define GP_TCLR_ST (1<<0) +#define GP_TCRR 0x028 /* counter */ +#define GP_TLDR 0x02c /* reload */ +#define GP_TTGR 0x030 +#define GP_TWPS 0x034 +#define GP_TWPS_TCLR 0x01 +#define GP_TWPS_TCRR 0x02 +#define GP_TWPS_TLDR 0x04 +#define GP_TWPS_TTGR 0x08 +#define GP_TWPS_TMAR 0x10 +#define GP_TWPS_ALL 0x1f +#define GP_TMAR 0x038 +#define GP_TCAR 0x03C +#define GP_TSICR 0x040 +#define GP_TSICR_POSTED 0x00000002 +#define GP_TSICR_SFT 0x00000001 +#define GP_TCAR2 0x044 + +#define TIMER_FREQUENCY 32768 /* 32kHz is used, selectable */ + +static struct evcount clk_count; +static struct evcount stat_count; +#define GPT1_IRQ 38 +#define GPTIMER0_IRQ 38 + +//static int clk_irq = GPT1_IRQ; /* XXX 37 */ + +void gptimer_attach(struct device *parent, struct device *self, void *args); +int gptimer_intr(void *frame); +void gptimer_wait(int reg); +void gptimer_cpu_initclocks(void); +void gptimer_delay(u_int); +void gptimer_setstatclockrate(int newhz); + +bus_space_tag_t gptimer_iot; +bus_space_handle_t gptimer_ioh0, gptimer_ioh1; +int gptimer_irq = 0; + +u_int gptimer_get_timecount(struct timecounter *); + +static struct timecounter gptimer_timecounter = { + gptimer_get_timecount, NULL, 0x7fffffff, 0, "gptimer", 0, NULL +}; + +volatile u_int32_t nexttickevent; +volatile u_int32_t nextstatevent; +u_int32_t ticks_per_second; +u_int32_t ticks_per_intr; +u_int32_t ticks_err_cnt; +u_int32_t ticks_err_sum; +u_int32_t statvar, statmin; + +struct cfattach gptimer_ca = { + sizeof (struct device), NULL, gptimer_attach +}; + +struct cfdriver gptimer_cd = { + NULL, "gptimer", DV_DULL +}; + +void +gptimer_attach(struct device *parent, struct device *self, void *args) +{ + struct omap_attach_args *oa = args; + bus_space_handle_t ioh; + u_int32_t rev; + + gptimer_iot = oa->oa_iot; + if (bus_space_map(gptimer_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &ioh)) + panic("gptimer_attach: bus_space_map failed!"); + + rev = bus_space_read_4(gptimer_iot, ioh, GP_TIDR); + + printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); + if (self->dv_unit == 0) { + gptimer_ioh0 = ioh; + gptimer_irq = oa->oa_dev->irq[0]; + bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, 0); + } else if (self->dv_unit == 1) { + /* start timer because it is used in delay */ + gptimer_ioh1 = ioh; + bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCRR, 0); + gptimer_wait(GP_TWPS_ALL); + bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TLDR, 0); + gptimer_wait(GP_TWPS_ALL); + bus_space_write_4(gptimer_iot, gptimer_ioh1, GP_TCLR, + GP_TCLR_AR | GP_TCLR_ST); + gptimer_wait(GP_TWPS_ALL); + + gptimer_timecounter.tc_frequency = TIMER_FREQUENCY; + tc_init(&gptimer_timecounter); + } + else + panic("attaching too many gptimers at 0x%x", + oa->oa_dev->mem[0].addr); + + arm_clock_register(gptimer_cpu_initclocks, gptimer_delay, + gptimer_setstatclockrate, NULL); +} + +/* + * See comment in arm/xscale/i80321_clock.c + * + * counter is count up, but with autoreload timers it is not possible + * to detect how many interrupts passed while interrupts were blocked. + * also it is not possible to atomically add to the register + * get get it to precisely fire at a non-fixed interval. + * + * To work around this two timers are used, GPT1 is used as a reference + * clock without reload , however we just ignore the interrupt it + * would (may?) generate. + * + * Internally this keeps track of when the next timer should fire + * and based on that time and the current value of the reference + * clock a number is written into the timer count register to schedule + * the next event. + */ + +int +gptimer_intr(void *frame) +{ + u_int32_t now, r; + u_int32_t nextevent, duration; + + /* clear interrupt */ + now = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); + + while ((int32_t) (nexttickevent - now) < 0) { + nexttickevent += ticks_per_intr; + ticks_err_sum += ticks_err_cnt; +#if 0 + if (ticks_err_sum > hz) { + u_int32_t match_error; + match_error = ticks_err_sum / hz + ticks_err_sum -= (match_error * hz); + } +#else + /* looping a few times is faster than divide */ + while (ticks_err_sum > hz) { + nexttickevent += 1; + ticks_err_sum -= hz; + } +#endif + clk_count.ec_count++; + hardclock(frame); + } + while ((int32_t) (nextstatevent - now) < 0) { + do { + r = random() & (statvar -1); + } while (r == 0); /* random == 0 not allowed */ + nextstatevent += statmin + r; + /* XXX - correct nextstatevent? */ + stat_count.ec_count++; + statclock(frame); + } + if ((now - nexttickevent) < (now - nextstatevent)) + nextevent = nexttickevent; + else + nextevent = nextstatevent; + +/* XXX */ + duration = nextevent - + bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); +#if 0 + printf("duration 0x%x %x %x\n", nextevent - + bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR), + bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TCRR), + bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR)); +#endif + + + if (duration <= 0) + duration = 1; /* trigger immediately. */ + + if (duration > ticks_per_intr) { + /* + * If interrupts are blocked too long, like during + * the root prompt or ddb, the timer can roll over, + * this will allow the system to continue to run + * even if time is lost. + */ + duration = ticks_per_intr; + nexttickevent = now; + nextstatevent = now; + } + + gptimer_wait(GP_TWPS_ALL); + bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR, + bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR)); + gptimer_wait(GP_TWPS_ALL); + bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -duration); + + return 1; +} + +/* + * would be interesting to play with trigger mode while having one timer + * in 32KHz mode, and the other timer running in sysclk mode and use + * the high resolution speeds (matters more for delay than tick timer + */ + +void +gptimer_cpu_initclocks() +{ +// u_int32_t now; + stathz = 128; + profhz = 1024; + + ticks_per_second = TIMER_FREQUENCY; + + setstatclockrate(stathz); + + ticks_per_intr = ticks_per_second / hz; + ticks_err_cnt = ticks_per_second % hz; + ticks_err_sum = 0;; + + prcm_setclock(1, PRCM_CLK_SPEED_32); + prcm_setclock(2, PRCM_CLK_SPEED_32); + /* establish interrupts */ + arm_intr_establish(gptimer_irq, IPL_CLOCK, gptimer_intr, + NULL, "tick"); + + /* setup timer 0 (hardware timer 2) */ + /* reset? - XXX */ + + bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TLDR, 0); + + nexttickevent = nextstatevent = bus_space_read_4(gptimer_iot, + gptimer_ioh1, GP_TCRR) + ticks_per_intr; + + gptimer_wait(GP_TWPS_ALL); + bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TIER, GP_TIER_OVF_EN); + gptimer_wait(GP_TWPS_ALL); + bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TWER, GP_TWER_OVF_EN); + gptimer_wait(GP_TWPS_ALL); + bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCLR, + GP_TCLR_AR | GP_TCLR_ST); + gptimer_wait(GP_TWPS_ALL); + bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TISR, + bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TISR)); + gptimer_wait(GP_TWPS_ALL); + bus_space_write_4(gptimer_iot, gptimer_ioh0, GP_TCRR, -ticks_per_intr); + gptimer_wait(GP_TWPS_ALL); +} + +void +gptimer_wait(int reg) +{ + while (bus_space_read_4(gptimer_iot, gptimer_ioh0, GP_TWPS) & reg) + ; +} + +#if 0 +void +microtime(struct timeval *tvp) +{ + int s; + int deltacnt; + u_int32_t counter, expected; + s = splhigh(); + + if (1) { /* not inited */ + tvp->tv_sec = 0; + tvp->tv_usec = 0; + return; + } + s = splhigh(); + counter = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); + expected = nexttickevent; + + *tvp = time; + splx(s); + + deltacnt = counter - expected + ticks_per_intr; + +#if 1 + /* low frequency timer algorithm */ + tvp->tv_usec += deltacnt * 1000000ULL / TIMER_FREQUENCY; +#else + /* high frequency timer algorithm - XXX */ + tvp->tv_usec += deltacnt / (TIMER_FREQUENCY / 1000000ULL); +#endif + + while (tvp->tv_usec >= 1000000) { + tvp->tv_sec++; + tvp->tv_usec -= 1000000; + } + +} +#endif + +void +gptimer_delay(u_int usecs) +{ + u_int32_t clock, oclock, delta, delaycnt; + volatile int j; + int csec, usec; + + if (usecs > (0x80000000 / (TIMER_FREQUENCY))) { + csec = usecs / 10000; + usec = usecs % 10000; + + delaycnt = (TIMER_FREQUENCY / 100) * csec + + (TIMER_FREQUENCY / 100) * usec / 10000; + } else { + delaycnt = TIMER_FREQUENCY * usecs / 1000000; + } + if (delaycnt <= 1) + for (j = 100; j > 0; j--) + ; + + if (gptimer_ioh1 == 0) { + /* BAH */ + for (; usecs > 0; usecs--) + for (j = 100; j > 0; j--) + ; + return; + } + oclock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); + while (1) { + for (j = 100; j > 0; j--) + ; + clock = bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); + delta = clock - oclock; + if (delta > delaycnt) + break; + } + +} + +void +gptimer_setstatclockrate(int newhz) +{ + int minint, statint; + int s; + + s = splclock(); + + statint = ticks_per_second / newhz; + /* calculate largest 2^n which is smaller that just over half statint */ + statvar = 0x40000000; /* really big power of two */ + minint = statint / 2 + 100; + while (statvar > minint) + statvar >>= 1; + + statmin = statint - (statvar >> 1); + + splx(s); + + /* + * XXX this allows the next stat timer to occur then it switches + * to the new frequency. Rather than switching instantly. + */ +} + + +u_int +gptimer_get_timecount(struct timecounter *tc) +{ + return bus_space_read_4(gptimer_iot, gptimer_ioh1, GP_TCRR); +} diff --git a/sys/arch/armv7/omap/if_cpsw.c b/sys/arch/armv7/omap/if_cpsw.c new file mode 100644 index 00000000000..67fc5a97467 --- /dev/null +++ b/sys/arch/armv7/omap/if_cpsw.c @@ -0,0 +1,1264 @@ +/* $OpenBSD: if_cpsw.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* $NetBSD: if_cpsw.c,v 1.3 2013/04/17 14:36:34 bouyer Exp $ */ + +/* + * Copyright (c) 2013 Jonathan A. Kollasch + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS + * "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 THE COPYRIGHT HOLDER OR + * CONTRIBUTORS 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. + */ + +/*- + * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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 "bpfilter.h" + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/sockio.h> +#include <sys/mbuf.h> +#include <sys/queue.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/timeout.h> +#include <sys/socket.h> + +#include <machine/bus.h> + +#include <net/if.h> +#include <net/if_media.h> + +#include <netinet/in.h> +#include <netinet/if_ether.h> + +#if NBPFILTER > 0 +#include <net/bpf.h> +#endif + +#include <dev/mii/mii.h> +#include <dev/mii/miivar.h> + +#include <arch/armv7/omap/omapvar.h> +#include <arch/armv7/omap/sitara_cm.h> +#include <arch/armv7/omap/if_cpswreg.h> + +#define CPSW_TXFRAGS 16 + +#define OMAP2SCM_MAC_ID0_LO 0x630 +#define OMAP2SCM_MAC_ID0_HI 0x634 + +#define CPSW_CPPI_RAM_SIZE (0x2000) +#define CPSW_CPPI_RAM_TXDESCS_SIZE (CPSW_CPPI_RAM_SIZE/2) +#define CPSW_CPPI_RAM_RXDESCS_SIZE \ + (CPSW_CPPI_RAM_SIZE - CPSW_CPPI_RAM_TXDESCS_SIZE) +#define CPSW_CPPI_RAM_TXDESCS_BASE (CPSW_CPPI_RAM_OFFSET + 0x0000) +#define CPSW_CPPI_RAM_RXDESCS_BASE \ + (CPSW_CPPI_RAM_OFFSET + CPSW_CPPI_RAM_TXDESCS_SIZE) + +#define CPSW_NTXDESCS (CPSW_CPPI_RAM_TXDESCS_SIZE/sizeof(struct cpsw_cpdma_bd)) +#define CPSW_NRXDESCS (CPSW_CPPI_RAM_RXDESCS_SIZE/sizeof(struct cpsw_cpdma_bd)) + +#define CPSW_PAD_LEN (ETHER_MIN_LEN - ETHER_CRC_LEN) + +#define TXDESC_NEXT(x) cpsw_txdesc_adjust((x), 1) +#define TXDESC_PREV(x) cpsw_txdesc_adjust((x), -1) + +#define RXDESC_NEXT(x) cpsw_rxdesc_adjust((x), 1) +#define RXDESC_PREV(x) cpsw_rxdesc_adjust((x), -1) + +/* __BIT(n): nth bit, where __BIT(0) == 0x1. */ +#define __BIT(__n) \ + (((uint32_t)(__n) >= NBBY * sizeof(uint32_t)) ? 0 : ((uint32_t)1 << (uint32_t)(__n))) + +/* __BITS(m, n): bits m through n, m < n. */ +#define __BITS(__m, __n) \ + ((__BIT(MAX((__m), (__n)) + 1) - 1) ^ (__BIT(MIN((__m), (__n))) - 1)) + +/* find least significant bit that is set */ +#define __LOWEST_SET_BIT(__mask) ((((__mask) - 1) & (__mask)) ^ (__mask)) + +#define __PRIuBIT PRIuMAX +#define __PRIuBITS __PRIuBIT + +#define __PRIxBIT PRIxMAX +#define __PRIxBITS __PRIxBIT + +#define __SHIFTOUT(__x, __mask) (((__x) & (__mask)) / __LOWEST_SET_BIT(__mask)) + +struct cpsw_ring_data { + bus_dmamap_t tx_dm[CPSW_NTXDESCS]; + struct mbuf *tx_mb[CPSW_NTXDESCS]; + bus_dmamap_t rx_dm[CPSW_NRXDESCS]; + struct mbuf *rx_mb[CPSW_NRXDESCS]; +}; + +struct cpsw_softc { + struct device sc_dev; + const char sc_name; + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + bus_dma_tag_t sc_bdt; + bus_space_handle_t sc_bsh_txdescs; + bus_space_handle_t sc_bsh_rxdescs; + bus_addr_t sc_txdescs_pa; + bus_addr_t sc_rxdescs_pa; + struct arpcom sc_ec; + struct mii_data sc_mii; + void *sc_ih; + struct cpsw_ring_data *sc_rdp; + volatile u_int sc_txnext; + volatile u_int sc_txhead; + volatile u_int sc_rxhead; + void *sc_rxthih; + void *sc_rxih; + void *sc_txih; + void *sc_miscih; + void *sc_txpad; + bus_dmamap_t sc_txpad_dm; +#define sc_txpad_pa sc_txpad_dm->dm_segs[0].ds_addr + uint8_t sc_enaddr[ETHER_ADDR_LEN]; + volatile bool sc_txrun; + volatile bool sc_rxrun; + volatile bool sc_txeoq; + volatile bool sc_rxeoq; + struct timeout sc_tick; +}; + +void cpsw_get_mac_addr(struct cpsw_softc *); +void cpsw_attach(struct device *, struct device *, void *); + +void cpsw_start(struct ifnet *); +int cpsw_ioctl(struct ifnet *, u_long, caddr_t); +void cpsw_watchdog(struct ifnet *); +int cpsw_init(struct ifnet *); +void cpsw_stop(struct ifnet *); + +int cpsw_mii_readreg(struct device *, int, int); +void cpsw_mii_writereg(struct device *, int, int, int); +void cpsw_mii_statchg(struct device *); + +void cpsw_tick(void *); + +int cpsw_new_rxbuf(struct cpsw_softc * const, const u_int); +int cpsw_mediachange(struct ifnet *); +void cpsw_mediastatus(struct ifnet *, struct ifmediareq *); + +int cpsw_rxthintr(void *); +int cpsw_rxintr(void *); +int cpsw_txintr(void *); +int cpsw_miscintr(void *); + +struct cfattach cpsw_ca = { + sizeof (struct cpsw_softc), NULL, cpsw_attach +}; + +struct cfdriver cpsw_cd = { + NULL, "cpsw", DV_IFNET +}; + +/* + * * Return the number of bytes in the mbuf chain, m. + * */ +static __inline u_int +m_length(const struct mbuf *m) +{ + const struct mbuf *m0; + u_int pktlen; + + if ((m->m_flags & M_PKTHDR) != 0) + return m->m_pkthdr.len; + + pktlen = 0; + for (m0 = m; m0 != NULL; m0 = m0->m_next) + pktlen += m0->m_len; + return pktlen; +} + +static inline u_int +cpsw_txdesc_adjust(u_int x, int y) +{ + return (((x) + y) & (CPSW_NTXDESCS - 1)); +} + +static inline u_int +cpsw_rxdesc_adjust(u_int x, int y) +{ + return (((x) + y) & (CPSW_NRXDESCS - 1)); +} + +static inline uint32_t +cpsw_read_4(struct cpsw_softc * const sc, bus_size_t const offset) +{ + return bus_space_read_4(sc->sc_bst, sc->sc_bsh, offset); +} + +static inline void +cpsw_write_4(struct cpsw_softc * const sc, bus_size_t const offset, + uint32_t const value) +{ + bus_space_write_4(sc->sc_bst, sc->sc_bsh, offset, value); +} + +static inline void +cpsw_set_txdesc_next(struct cpsw_softc * const sc, const u_int i, uint32_t n) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i + 0; + bus_space_write_4(sc->sc_bst, sc->sc_bsh_txdescs, o, n); +} + +static inline void +cpsw_set_rxdesc_next(struct cpsw_softc * const sc, const u_int i, uint32_t n) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i + 0; + bus_space_write_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, n); +} + +static inline void +cpsw_get_txdesc(struct cpsw_softc * const sc, const u_int i, + struct cpsw_cpdma_bd * const bdp) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i; + uint32_t * const dp = bdp->word; + const bus_size_t c = nitems(bdp->word); + + bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o, dp, c); +} + +static inline void +cpsw_set_txdesc(struct cpsw_softc * const sc, const u_int i, + struct cpsw_cpdma_bd * const bdp) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i; + uint32_t * const dp = bdp->word; + const bus_size_t c = nitems(bdp->word); + + bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_txdescs, o, dp, c); +} + +static inline void +cpsw_get_rxdesc(struct cpsw_softc * const sc, const u_int i, + struct cpsw_cpdma_bd * const bdp) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i; + uint32_t * const dp = bdp->word; + const bus_size_t c = nitems(bdp->word); + + bus_space_read_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, dp, c); +} + +static inline void +cpsw_set_rxdesc(struct cpsw_softc * const sc, const u_int i, + struct cpsw_cpdma_bd * const bdp) +{ + const bus_size_t o = sizeof(struct cpsw_cpdma_bd) * i; + uint32_t * const dp = bdp->word; + const bus_size_t c = nitems(bdp->word); + + bus_space_write_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, o, dp, c); +} + +static inline bus_addr_t +cpsw_txdesc_paddr(struct cpsw_softc * const sc, u_int x) +{ + KASSERT(x < CPSW_NTXDESCS); + return sc->sc_txdescs_pa + sizeof(struct cpsw_cpdma_bd) * x; +} + +static inline bus_addr_t +cpsw_rxdesc_paddr(struct cpsw_softc * const sc, u_int x) +{ + KASSERT(x < CPSW_NRXDESCS); + return sc->sc_rxdescs_pa + sizeof(struct cpsw_cpdma_bd) * x; +} + +void +cpsw_get_mac_addr(struct cpsw_softc *sc) +{ + u_int32_t mac_lo = 0, mac_hi = 0; + + sitara_cm_reg_read_4(OMAP2SCM_MAC_ID0_LO, &mac_lo); + sitara_cm_reg_read_4(OMAP2SCM_MAC_ID0_HI, &mac_hi); + + if ((mac_lo == 0) && (mac_hi == 0)) { + CPSW_PRINTF(sc, "%s(%d): Invalid Ethernet address!\n", + __FILE__, __LINE__); + } else { + sc->sc_enaddr[0] = (mac_hi >> 0) & 0xff; + sc->sc_enaddr[1] = (mac_hi >> 8) & 0xff; + sc->sc_enaddr[2] = (mac_hi >> 16) & 0xff; + sc->sc_enaddr[3] = (mac_hi >> 24) & 0xff; + sc->sc_enaddr[4] = (mac_lo >> 0) & 0xff; + sc->sc_enaddr[5] = (mac_lo >> 8) & 0xff; + } +} + +void +cpsw_attach(struct device *parent, struct device *self, void *aux) +{ + struct cpsw_softc *sc = (struct cpsw_softc *)self; + struct omap_attach_args *oa = aux; + struct arpcom * const ec = &sc->sc_ec; + struct ifnet * const ifp = &ec->ac_if; + int error; + u_int i; + + timeout_set(&sc->sc_tick, cpsw_tick, sc); + + cpsw_get_mac_addr(sc); + +#if 0 + /* XXX Start here, we need to setup the interrupt properly */ + sc->sc_ihc0 = arm_intr_establish(aa->aa_intr, IPL_USB, + ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); + int irqno, + int level, + int (*func)(void *), + void *cookie, + char *name; +#endif + sc->sc_rxthih = arm_intr_establish(oa->oa_dev->irq[0] + CPSW_INTROFF_RXTH, + IPL_NET, cpsw_rxthintr, sc, sc->sc_dev.dv_xname); + sc->sc_rxih = arm_intr_establish(oa->oa_dev->irq[0] + CPSW_INTROFF_RX, + IPL_NET, cpsw_rxintr, sc, sc->sc_dev.dv_xname); + sc->sc_txih = arm_intr_establish(oa->oa_dev->irq[0] + CPSW_INTROFF_TX, + IPL_NET, cpsw_txintr, sc, sc->sc_dev.dv_xname); + sc->sc_miscih = arm_intr_establish(oa->oa_dev->irq[0] + CPSW_INTROFF_MISC, + IPL_NET, cpsw_miscintr, sc, sc->sc_dev.dv_xname); + + sc->sc_bst = oa->oa_iot; + sc->sc_bdt = oa->oa_dmat; + + error = bus_space_map(sc->sc_bst, oa->oa_dev->mem[0].addr, oa->oa_dev->mem[0].size, 0, + &sc->sc_bsh); + if (error) { + printf("can't map registers: %d\n", error); + return; + } + + sc->sc_txdescs_pa = oa->oa_dev->mem[0].addr + CPSW_CPPI_RAM_TXDESCS_BASE; + error = bus_space_subregion(sc->sc_bst, sc->sc_bsh, + CPSW_CPPI_RAM_TXDESCS_BASE, CPSW_CPPI_RAM_TXDESCS_SIZE, + &sc->sc_bsh_txdescs); + if (error) { + printf("can't subregion tx ring SRAM: %d\n", error); + return; + } + printf(" txdescs at %p", (void *)sc->sc_bsh_txdescs); + + sc->sc_rxdescs_pa = oa->oa_dev->mem[0].addr + CPSW_CPPI_RAM_RXDESCS_BASE; + error = bus_space_subregion(sc->sc_bst, sc->sc_bsh, + CPSW_CPPI_RAM_RXDESCS_BASE, CPSW_CPPI_RAM_RXDESCS_SIZE, + &sc->sc_bsh_rxdescs); + if (error) { + printf("can't subregion rx ring SRAM: %d\n", error); + return; + } + printf(" rxdescs at %p", (void *)sc->sc_bsh_rxdescs); + + sc->sc_rdp = malloc(sizeof(*sc->sc_rdp), M_TEMP, M_WAITOK); + KASSERT(sc->sc_rdp != NULL); + + for (i = 0; i < CPSW_NTXDESCS; i++) { + if ((error = bus_dmamap_create(sc->sc_bdt, MCLBYTES, + CPSW_TXFRAGS, MCLBYTES, 0, 0, + &sc->sc_rdp->tx_dm[i])) != 0) { + printf("unable to create tx DMA map: %d\n", error); + } + sc->sc_rdp->tx_mb[i] = NULL; + } + + for (i = 0; i < CPSW_NRXDESCS; i++) { + if ((error = bus_dmamap_create(sc->sc_bdt, MCLBYTES, 1, + MCLBYTES, 0, 0, &sc->sc_rdp->rx_dm[i])) != 0) { + printf("unable to create rx DMA map: %d\n", error); + } + sc->sc_rdp->rx_mb[i] = NULL; + } + + /* XXX Not sure if this is the correct way to do this. orig below. + sc->sc_txpad = kmem_zalloc(ETHER_MIN_LEN, KM_SLEEP); + */ + sc->sc_txpad = malloc(ETHER_MIN_LEN, M_TEMP, M_WAITOK); + KASSERT(sc->sc_txpad != NULL); + bus_dmamap_create(sc->sc_bdt, ETHER_MIN_LEN, 1, ETHER_MIN_LEN, 0, + BUS_DMA_WAITOK, &sc->sc_txpad_dm); + bus_dmamap_load(sc->sc_bdt, sc->sc_txpad_dm, sc->sc_txpad, + ETHER_MIN_LEN, NULL, BUS_DMA_WAITOK|BUS_DMA_WRITE); + bus_dmamap_sync(sc->sc_bdt, sc->sc_txpad_dm, 0, ETHER_MIN_LEN, + BUS_DMASYNC_PREWRITE); + + printf(", address %s\n", ether_sprintf(sc->sc_enaddr)); + + ifp->if_softc = sc; + ifp->if_capabilities = 0; + ifp->if_flags = IFF_BROADCAST | IFF_SIMPLEX | IFF_MULTICAST; + ifp->if_start = cpsw_start; + ifp->if_ioctl = cpsw_ioctl; + ifp->if_watchdog = cpsw_watchdog; + IFQ_SET_MAXLEN(&ifp->if_snd, CPSW_NTXDESCS - 1); + IFQ_SET_READY(&ifp->if_snd); + memcpy(ifp->if_xname, sc->sc_dev.dv_xname, IFNAMSIZ); + + cpsw_stop(ifp); + + sc->sc_mii.mii_ifp = ifp; + sc->sc_mii.mii_readreg = cpsw_mii_readreg; + sc->sc_mii.mii_writereg = cpsw_mii_writereg; + sc->sc_mii.mii_statchg = cpsw_mii_statchg; + +#if 0 + sc->sc_ec.ec_mii = &sc->sc_mii; +#endif + ifmedia_init(&sc->sc_mii.mii_media, 0, cpsw_mediachange, + cpsw_mediastatus); + mii_attach(self, &sc->sc_mii, 0xffffffff, MII_PHY_ANY, MII_OFFSET_ANY, 0); + if (LIST_FIRST(&sc->sc_mii.mii_phys) == NULL) { + printf("no PHY found!\n"); + ifmedia_add(&sc->sc_mii.mii_media, + IFM_ETHER|IFM_MANUAL, 0, NULL); + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_MANUAL); + } else { + ifmedia_set(&sc->sc_mii.mii_media, IFM_ETHER|IFM_AUTO); + } + + memcpy(sc->sc_ec.ac_enaddr, sc->sc_enaddr, ETHER_ADDR_LEN); + if_attach(ifp); + ether_ifattach(ifp); + + return; +} + +int +cpsw_mediachange(struct ifnet *ifp) +{ + struct cpsw_softc *sc = ifp->if_softc; + + if (LIST_FIRST(&sc->sc_mii.mii_phys)) + mii_mediachg(&sc->sc_mii); + + return (0); +} + +void +cpsw_mediastatus(struct ifnet *ifp, struct ifmediareq *ifmr) +{ + struct cpsw_softc *sc = ifp->if_softc; + + if (LIST_FIRST(&sc->sc_mii.mii_phys)) { + mii_pollstat(&sc->sc_mii); + ifmr->ifm_active = sc->sc_mii.mii_media_active; + ifmr->ifm_status = sc->sc_mii.mii_media_status; + } +} + +void +cpsw_start(struct ifnet *ifp) +{ + struct cpsw_softc * const sc = ifp->if_softc; + struct cpsw_ring_data * const rdp = sc->sc_rdp; + struct cpsw_cpdma_bd bd; + uint32_t * const dw = bd.word; + struct mbuf *m; + bus_dmamap_t dm; + u_int sopi; /* Start of Packet Index */ + u_int eopi = ~0; + u_int seg; + u_int txfree; + int txstart = -1; + int error; + bool pad; + u_int mlen; + + if (__predict_false((ifp->if_flags & (IFF_RUNNING|IFF_OACTIVE)) != + IFF_RUNNING)) { + return; + } + + if (sc->sc_txnext >= sc->sc_txhead) + txfree = CPSW_NTXDESCS - 1 + sc->sc_txhead - sc->sc_txnext; + else + txfree = sc->sc_txhead - sc->sc_txnext - 1; + + while (txfree > 0) { + IFQ_POLL(&ifp->if_snd, m); + if (m == NULL) + break; + + dm = rdp->tx_dm[sc->sc_txnext]; + + error = bus_dmamap_load_mbuf(sc->sc_bdt, dm, m, BUS_DMA_NOWAIT); + if (error == EFBIG) { + printf("won't fit\n"); + IFQ_DEQUEUE(&ifp->if_snd, m); + m_freem(m); + ifp->if_oerrors++; + continue; + } else if (error != 0) { + printf("error\n"); + break; + } + + if (dm->dm_nsegs + 1 >= txfree) { + ifp->if_flags |= IFF_OACTIVE; + bus_dmamap_unload(sc->sc_bdt, dm); + break; + } + + mlen = m_length(m); + pad = mlen < CPSW_PAD_LEN; + + KASSERT(rdp->tx_mb[sc->sc_txnext] == NULL); + rdp->tx_mb[sc->sc_txnext] = m; + IFQ_DEQUEUE(&ifp->if_snd, m); + + bus_dmamap_sync(sc->sc_bdt, dm, 0, dm->dm_mapsize, + BUS_DMASYNC_PREWRITE); + + if (txstart == -1) + txstart = sc->sc_txnext; + sopi = eopi = sc->sc_txnext; + for (seg = 0; seg < dm->dm_nsegs; seg++) { + dw[0] = cpsw_txdesc_paddr(sc, + TXDESC_NEXT(sc->sc_txnext)); + dw[1] = dm->dm_segs[seg].ds_addr; + dw[2] = dm->dm_segs[seg].ds_len; + dw[3] = 0; + + if (seg == 0) + dw[3] |= CPDMA_BD_SOP | CPDMA_BD_OWNER | + MAX(mlen, CPSW_PAD_LEN); + + if (seg == dm->dm_nsegs - 1 && !pad) + dw[3] |= CPDMA_BD_EOP; + + cpsw_set_txdesc(sc, sc->sc_txnext, &bd); + txfree--; + eopi = sc->sc_txnext; + sc->sc_txnext = TXDESC_NEXT(sc->sc_txnext); + } + if (pad) { + dw[0] = cpsw_txdesc_paddr(sc, + TXDESC_NEXT(sc->sc_txnext)); + dw[1] = sc->sc_txpad_pa; + dw[2] = CPSW_PAD_LEN - mlen; + dw[3] = CPDMA_BD_EOP; + + cpsw_set_txdesc(sc, sc->sc_txnext, &bd); + txfree--; + eopi = sc->sc_txnext; + sc->sc_txnext = TXDESC_NEXT(sc->sc_txnext); + } +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_OUT); +#endif + } + + if (txstart >= 0) { + ifp->if_timer = 5; + /* terminate the new chain */ + KASSERT(eopi == TXDESC_PREV(sc->sc_txnext)); + cpsw_set_txdesc_next(sc, TXDESC_PREV(sc->sc_txnext), 0); + + /* link the new chain on */ + cpsw_set_txdesc_next(sc, TXDESC_PREV(txstart), + cpsw_txdesc_paddr(sc, txstart)); + if (sc->sc_txeoq) { + /* kick the dma engine */ + sc->sc_txeoq = false; + cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(0), + cpsw_txdesc_paddr(sc, txstart)); + } + } +} + +int +cpsw_ioctl(struct ifnet *ifp, u_long cmd, caddr_t data) +{ + struct cpsw_softc *sc = ifp->if_softc; + struct ifaddr *ifa = (struct ifaddr *)data; + struct ifreq *ifr = (struct ifreq *)data; + int s = splnet(); + int error = 0; + + switch (cmd) { + case SIOCSIFADDR: + ifp->if_flags |= IFF_UP; +#ifdef INET + if (ifa->ifa_addr->sa_family == AF_INET) + arp_ifinit(&sc->sc_ec, ifa); +#endif + + case SIOCSIFFLAGS: + if (ifp->if_flags & IFF_UP) { + if (ifp->if_flags & IFF_RUNNING) + error = ENETRESET; + else + cpsw_init(ifp); + } else { + if (ifp->if_flags & IFF_RUNNING) + cpsw_stop(ifp); + } + break; + case SIOCSIFMEDIA: + ifr->ifr_media &= ~IFM_ETH_FMASK; + /* FALLTHROUGH */ + case SIOCGIFMEDIA: + error = ifmedia_ioctl(ifp, ifr, &sc->sc_mii.mii_media, cmd); + break; + default: + error = ether_ioctl(ifp, &sc->sc_ec, cmd, data); + break; + } + if (error == ENETRESET) { + if (ifp->if_flags & IFF_RUNNING) + cpsw_init(ifp); + error = 0; + } + + splx(s); + + return error; +} + +void +cpsw_watchdog(struct ifnet *ifp) +{ + printf("device timeout\n"); + + ifp->if_oerrors++; + cpsw_init(ifp); + cpsw_start(ifp); +} + +static int +cpsw_mii_wait(struct cpsw_softc * const sc, int reg) +{ + u_int tries; + + for(tries = 0; tries < 1000; tries++) { + if ((cpsw_read_4(sc, reg) & __BIT(31)) == 0) + return 0; + delay(1); + } + return ETIMEDOUT; +} + +int +cpsw_mii_readreg(struct device *dev, int phy, int reg) +{ + struct cpsw_softc * const sc = (struct cpsw_softc *)dev; + uint32_t v; + + if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0) + return 0; + + cpsw_write_4(sc, MDIOUSERACCESS0, (1 << 31) | + ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16)); + + if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0) + return 0; + + v = cpsw_read_4(sc, MDIOUSERACCESS0); + if (v & __BIT(29)) + return v & 0xffff; + else + return 0; +} + +void +cpsw_mii_writereg(struct device *dev, int phy, int reg, int val) +{ + struct cpsw_softc * const sc = (struct cpsw_softc *)dev; + uint32_t v; + + KASSERT((val & 0xffff0000UL) == 0); + + if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0) + goto out; + + cpsw_write_4(sc, MDIOUSERACCESS0, (1 << 31) | (1 << 30) | + ((reg & 0x1F) << 21) | ((phy & 0x1F) << 16) | val); + + if (cpsw_mii_wait(sc, MDIOUSERACCESS0) != 0) + goto out; + + v = cpsw_read_4(sc, MDIOUSERACCESS0); + if ((v & __BIT(29)) == 0) +out: + printf("%s error\n", __func__); + +} + +void +cpsw_mii_statchg(struct device *self) +{ + return; +} + +int +cpsw_new_rxbuf(struct cpsw_softc * const sc, const u_int i) +{ + struct cpsw_ring_data * const rdp = sc->sc_rdp; + const u_int h = RXDESC_PREV(i); + struct cpsw_cpdma_bd bd; + uint32_t * const dw = bd.word; + struct mbuf *m; + int error = ENOBUFS; + + MGETHDR(m, M_DONTWAIT, MT_DATA); + if (m == NULL) { + goto reuse; + } + + MCLGET(m, M_DONTWAIT); + if ((m->m_flags & M_EXT) == 0) { + m_freem(m); + goto reuse; + } + + /* We have a new buffer, prepare it for the ring. */ + + if (rdp->rx_mb[i] != NULL) + bus_dmamap_unload(sc->sc_bdt, rdp->rx_dm[i]); + + m->m_len = m->m_pkthdr.len = MCLBYTES; + + rdp->rx_mb[i] = m; + + error = bus_dmamap_load_mbuf(sc->sc_bdt, rdp->rx_dm[i], rdp->rx_mb[i], + BUS_DMA_READ|BUS_DMA_NOWAIT); + if (error) { + printf("can't load rx DMA map %d: %d\n", i, error); + } + + bus_dmamap_sync(sc->sc_bdt, rdp->rx_dm[i], + 0, rdp->rx_dm[i]->dm_mapsize, BUS_DMASYNC_PREREAD); + + error = 0; + +reuse: + /* (re-)setup the descriptor */ + dw[0] = 0; + dw[1] = rdp->rx_dm[i]->dm_segs[0].ds_addr; + dw[2] = MIN(0x7ff, rdp->rx_dm[i]->dm_segs[0].ds_len); + dw[3] = CPDMA_BD_OWNER; + + cpsw_set_rxdesc(sc, i, &bd); + /* and link onto ring */ + cpsw_set_rxdesc_next(sc, h, cpsw_rxdesc_paddr(sc, i)); + + return error; +} + +int +cpsw_init(struct ifnet *ifp) +{ + struct cpsw_softc * const sc = ifp->if_softc; + struct mii_data * const mii = &sc->sc_mii; + int i; + + cpsw_stop(ifp); + + sc->sc_txnext = 0; + sc->sc_txhead = 0; + + /* Reset wrapper */ + cpsw_write_4(sc, CPSW_WR_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_WR_SOFT_RESET) & 1); + + /* Reset SS */ + cpsw_write_4(sc, CPSW_SS_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_SS_SOFT_RESET) & 1); + + /* Clear table (30) and enable ALE(31) and set passthrough (4) */ + cpsw_write_4(sc, CPSW_ALE_CONTROL, (3 << 30) | 0x10); + + /* Reset and init Sliver port 1 and 2 */ + for (i = 0; i < 2; i++) { + /* Reset */ + cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1); + while(cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1); + /* Set Slave Mapping */ + cpsw_write_4(sc, CPSW_SL_RX_PRI_MAP(i), 0x76543210); + cpsw_write_4(sc, CPSW_PORT_P_TX_PRI_MAP(i+1), 0x33221100); + cpsw_write_4(sc, CPSW_SL_RX_MAXLEN(i), 0x5f2); + /* Set MAC Address */ + cpsw_write_4(sc, CPSW_PORT_P_SA_HI(i+1), + sc->sc_enaddr[0] | (sc->sc_enaddr[1] << 8) | + (sc->sc_enaddr[2] << 16) | (sc->sc_enaddr[3] << 24)); + cpsw_write_4(sc, CPSW_PORT_P_SA_LO(i+1), + sc->sc_enaddr[4] | (sc->sc_enaddr[5] << 8)); + + /* Set MACCONTROL for ports 0,1: FULLDUPLEX(1), GMII_EN(5), + IFCTL_A(15), IFCTL_B(16) FIXME */ + cpsw_write_4(sc, CPSW_SL_MACCONTROL(i), 1 | (1<<5) | (1<<15) | (1<<16)); + + /* Set ALE port to forwarding(3) */ + cpsw_write_4(sc, CPSW_ALE_PORTCTL(i+1), 3); + } + + /* Set Host Port Mapping */ + cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_TX_PRI_MAP, 0x76543210); + cpsw_write_4(sc, CPSW_PORT_P0_CPDMA_RX_CH_MAP, 0); + + /* Set ALE port to forwarding(3) */ + cpsw_write_4(sc, CPSW_ALE_PORTCTL(0), 3); + + cpsw_write_4(sc, CPSW_SS_PTYPE, 0); + cpsw_write_4(sc, CPSW_SS_STAT_PORT_EN, 7); + + cpsw_write_4(sc, CPSW_CPDMA_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_CPDMA_SOFT_RESET) & 1); + + for (i = 0; i < 8; i++) { + cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(i), 0); + cpsw_write_4(sc, CPSW_CPDMA_RX_HDP(i), 0); + cpsw_write_4(sc, CPSW_CPDMA_TX_CP(i), 0); + cpsw_write_4(sc, CPSW_CPDMA_RX_CP(i), 0); + } + + bus_space_set_region_4(sc->sc_bst, sc->sc_bsh_txdescs, 0, 0, + CPSW_CPPI_RAM_TXDESCS_SIZE/4); + + sc->sc_txhead = 0; + sc->sc_txnext = 0; + + cpsw_write_4(sc, CPSW_CPDMA_RX_FREEBUFFER(0), 0); + + bus_space_set_region_4(sc->sc_bst, sc->sc_bsh_rxdescs, 0, 0, + CPSW_CPPI_RAM_RXDESCS_SIZE/4); + + /* Initialize RX Buffer Descriptors */ + cpsw_set_rxdesc_next(sc, RXDESC_PREV(0), 0); + for (i = 0; i < CPSW_NRXDESCS; i++) { + cpsw_new_rxbuf(sc, i); + } + sc->sc_rxhead = 0; + + /* align layer 3 header to 32-bit */ + cpsw_write_4(sc, CPSW_CPDMA_RX_BUFFER_OFFSET, ETHER_ALIGN); + + /* Clear all interrupt Masks */ + cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_CLEAR, 0xFFFFFFFF); + cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_CLEAR, 0xFFFFFFFF); + + /* Enable TX & RX DMA */ + cpsw_write_4(sc, CPSW_CPDMA_TX_CONTROL, 1); + cpsw_write_4(sc, CPSW_CPDMA_RX_CONTROL, 1); + + /* Enable TX and RX interrupt receive for core 0 */ + cpsw_write_4(sc, CPSW_WR_C_TX_EN(0), 1); + cpsw_write_4(sc, CPSW_WR_C_RX_EN(0), 1); + cpsw_write_4(sc, CPSW_WR_C_MISC_EN(0), 0x1F); + + /* Enable host Error Interrupt */ + cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_SET, 2); + + /* Enable interrupts for TX and RX Channel 0 */ + cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_SET, 1); + cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_SET, 1); + + /* Ack stalled irqs */ + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RXTH); + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RX); + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX); + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC); + + /* Initialze MDIO - ENABLE, PREAMBLE=0, FAULTENB, CLKDIV=0xFF */ + /* TODO Calculate MDCLK=CLK/(CLKDIV+1) */ + cpsw_write_4(sc, MDIOCONTROL, (1<<30) | (1<<18) | 0xFF); + + mii_mediachg(mii); + + /* Write channel 0 RX HDP */ + cpsw_write_4(sc, CPSW_CPDMA_RX_HDP(0), cpsw_rxdesc_paddr(sc, 0)); + sc->sc_rxrun = true; + sc->sc_rxeoq = false; + + sc->sc_txrun = true; + sc->sc_txeoq = true; + + ifp->if_flags |= IFF_RUNNING; + ifp->if_flags &= ~IFF_OACTIVE; + + timeout_add_sec(&sc->sc_tick, 1); + + return 0; +} + +void +cpsw_stop(struct ifnet *ifp) +{ + struct cpsw_softc * const sc = ifp->if_softc; + struct cpsw_ring_data * const rdp = sc->sc_rdp; + u_int i; + +#if 0 + /* XXX find where disable comes from */ + printf("%s: ifp %p disable %d\n", __func__, ifp, disable); +#endif + if ((ifp->if_flags & IFF_RUNNING) == 0) + return; + + timeout_del(&sc->sc_tick); + + mii_down(&sc->sc_mii); + + cpsw_write_4(sc, CPSW_CPDMA_TX_INTMASK_CLEAR, 1); + cpsw_write_4(sc, CPSW_CPDMA_RX_INTMASK_CLEAR, 1); + cpsw_write_4(sc, CPSW_WR_C_TX_EN(0), 0x0); + cpsw_write_4(sc, CPSW_WR_C_RX_EN(0), 0x0); + cpsw_write_4(sc, CPSW_WR_C_MISC_EN(0), 0x1F); + + cpsw_write_4(sc, CPSW_CPDMA_TX_TEARDOWN, 0); + cpsw_write_4(sc, CPSW_CPDMA_RX_TEARDOWN, 0); + i = 0; + while ((sc->sc_txrun || sc->sc_rxrun) && i < 10000) { + delay(10); + if ((sc->sc_txrun == true) && cpsw_txintr(sc) == 0) + sc->sc_txrun = false; + if ((sc->sc_rxrun == true) && cpsw_rxintr(sc) == 0) + sc->sc_rxrun = false; + i++; + } + /* printf("%s toredown complete in %u\n", __func__, i); */ + + /* Reset wrapper */ + cpsw_write_4(sc, CPSW_WR_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_WR_SOFT_RESET) & 1); + + /* Reset SS */ + cpsw_write_4(sc, CPSW_SS_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_SS_SOFT_RESET) & 1); + + for (i = 0; i < 2; i++) { + cpsw_write_4(sc, CPSW_SL_SOFT_RESET(i), 1); + while(cpsw_read_4(sc, CPSW_SL_SOFT_RESET(i)) & 1); + } + + /* Reset CPDMA */ + cpsw_write_4(sc, CPSW_CPDMA_SOFT_RESET, 1); + while(cpsw_read_4(sc, CPSW_CPDMA_SOFT_RESET) & 1); + + /* Release any queued transmit buffers. */ + for (i = 0; i < CPSW_NTXDESCS; i++) { + bus_dmamap_unload(sc->sc_bdt, rdp->tx_dm[i]); + m_freem(rdp->tx_mb[i]); + rdp->tx_mb[i] = NULL; + } + + ifp->if_flags &= ~(IFF_RUNNING|IFF_OACTIVE); + ifp->if_timer = 0; + + /* XXX Not sure what this is doing calling disable here + where is disable set? + */ +#if 0 + if (!disable) + return; +#endif + + for (i = 0; i < CPSW_NRXDESCS; i++) { + bus_dmamap_unload(sc->sc_bdt, rdp->rx_dm[i]); + m_freem(rdp->rx_mb[i]); + rdp->rx_mb[i] = NULL; + } +} + +int +cpsw_rxthintr(void *arg) +{ + struct cpsw_softc * const sc = arg; + + /* this won't deassert the interrupt though */ + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RXTH); + + return 1; +} + +int +cpsw_rxintr(void *arg) +{ + struct cpsw_softc * const sc = arg; + struct ifnet * const ifp = &sc->sc_ec.ac_if; + struct cpsw_ring_data * const rdp = sc->sc_rdp; + struct cpsw_cpdma_bd bd; + const uint32_t * const dw = bd.word; + bus_dmamap_t dm; + struct mbuf *m; + u_int i; + u_int len, off; + + for (;;) { + KASSERT(sc->sc_rxhead < CPSW_NRXDESCS); + + i = sc->sc_rxhead; + dm = rdp->rx_dm[i]; + m = rdp->rx_mb[i]; + + KASSERT(dm != NULL); + KASSERT(m != NULL); + + cpsw_get_rxdesc(sc, i, &bd); + + if (ISSET(dw[3], CPDMA_BD_OWNER)) + break; + + if (ISSET(dw[3], CPDMA_BD_TDOWNCMPLT)) { + sc->sc_rxrun = false; + return 1; + } + + if ((dw[3] & (CPDMA_BD_SOP|CPDMA_BD_EOP)) != + (CPDMA_BD_SOP|CPDMA_BD_EOP)) { + /* Debugger(); */ + } + + bus_dmamap_sync(sc->sc_bdt, dm, 0, dm->dm_mapsize, + BUS_DMASYNC_POSTREAD); + + if (cpsw_new_rxbuf(sc, i) != 0) { + /* drop current packet, reuse buffer for new */ + ifp->if_ierrors++; + goto next; + } + + off = __SHIFTOUT(dw[2], (uint32_t)__BITS(26, 16)); + len = __SHIFTOUT(dw[3], (uint32_t)__BITS(10, 0)); + + if (ISSET(dw[3], CPDMA_BD_PASSCRC)) + len -= ETHER_CRC_LEN; + + m->m_pkthdr.rcvif = ifp; + m->m_pkthdr.len = m->m_len = len; + m->m_data += off; + + ifp->if_ipackets++; + +#if NBPFILTER > 0 + if (ifp->if_bpf) + bpf_mtap(ifp->if_bpf, m, BPF_DIRECTION_IN); +#endif + ether_input_mbuf(ifp, m); + +next: + sc->sc_rxhead = RXDESC_NEXT(sc->sc_rxhead); + if (ISSET(dw[3], CPDMA_BD_EOQ)) { + sc->sc_rxeoq = true; + break; + } else { + sc->sc_rxeoq = false; + } + cpsw_write_4(sc, CPSW_CPDMA_RX_CP(0), + cpsw_rxdesc_paddr(sc, i)); + } + + if (sc->sc_rxeoq) { + printf("rxeoq\n"); + /* Debugger(); */ + } + + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_RX); + + return 1; +} + +void +cpsw_tick(void *arg) +{ + struct cpsw_softc *sc = arg; + int s; + + s = splnet(); + mii_tick(&sc->sc_mii); + splx(s); + + timeout_add_sec(&sc->sc_tick, 1); +} + +int +cpsw_txintr(void *arg) +{ + struct cpsw_softc * const sc = arg; + struct ifnet * const ifp = &sc->sc_ec.ac_if; + struct cpsw_ring_data * const rdp = sc->sc_rdp; + struct cpsw_cpdma_bd bd; + const uint32_t * const dw = bd.word; + bool handled = false; + uint32_t tx0_cp; + u_int cpi; + + KASSERT(sc->sc_txrun); + + tx0_cp = cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0)); + + if (tx0_cp == 0xfffffffc) { + cpsw_write_4(sc, CPSW_CPDMA_TX_CP(0), 0xfffffffc); + cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(0), 0); + sc->sc_txrun = false; + return 0; + } + + cpi = (tx0_cp - sc->sc_txdescs_pa) / sizeof(struct cpsw_cpdma_bd); + + for (;;) { + tx0_cp = cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0)); + cpi = (tx0_cp - sc->sc_txdescs_pa) / sizeof(struct cpsw_cpdma_bd); + KASSERT(sc->sc_txhead < CPSW_NTXDESCS); + + + cpsw_get_txdesc(sc, sc->sc_txhead, &bd); + + if (dw[2] == 0) { + /* Debugger(); */ + } + + if (ISSET(dw[3], CPDMA_BD_SOP) == 0) + goto next; + + if (ISSET(dw[3], CPDMA_BD_OWNER)) { + printf("pwned %x %x %x\n", cpi, sc->sc_txhead, sc->sc_txnext); + break; + } + + if (ISSET(dw[3], CPDMA_BD_TDOWNCMPLT)) { + sc->sc_txrun = false; + return 1; + } + + bus_dmamap_sync(sc->sc_bdt, rdp->tx_dm[sc->sc_txhead], + 0, rdp->tx_dm[sc->sc_txhead]->dm_mapsize, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_bdt, rdp->tx_dm[sc->sc_txhead]); + + m_freem(rdp->tx_mb[sc->sc_txhead]); + rdp->tx_mb[sc->sc_txhead] = NULL; + + ifp->if_opackets++; + + handled = true; + + ifp->if_flags &= ~IFF_OACTIVE; + +next: + if (ISSET(dw[3], CPDMA_BD_EOP) && ISSET(dw[3], CPDMA_BD_EOQ)) { + sc->sc_txeoq = true; + } + if (sc->sc_txhead == cpi) { + cpsw_write_4(sc, CPSW_CPDMA_TX_CP(0), + cpsw_txdesc_paddr(sc, cpi)); + sc->sc_txhead = TXDESC_NEXT(sc->sc_txhead); + break; + } + sc->sc_txhead = TXDESC_NEXT(sc->sc_txhead); + if (ISSET(dw[3], CPDMA_BD_EOP) && ISSET(dw[3], CPDMA_BD_EOQ)) { + sc->sc_txeoq = true; + break; + } + } + + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_TX); + + if ((sc->sc_txnext != sc->sc_txhead) && sc->sc_txeoq) { + if (cpsw_read_4(sc, CPSW_CPDMA_TX_HDP(0)) == 0) { + sc->sc_txeoq = false; + cpsw_write_4(sc, CPSW_CPDMA_TX_HDP(0), + cpsw_txdesc_paddr(sc, sc->sc_txhead)); + } + } + + if (handled && sc->sc_txnext == sc->sc_txhead) + ifp->if_timer = 0; + + if (handled) + cpsw_start(ifp); + + return handled; +} + +int +cpsw_miscintr(void *arg) +{ + struct cpsw_softc * const sc = arg; + uint32_t miscstat; + uint32_t dmastat; + uint32_t stat; + + miscstat = cpsw_read_4(sc, CPSW_WR_C_MISC_STAT(0)); + printf("%s %x FIRE\n", __func__, miscstat); + +#define CPSW_MISC_HOST_PEND __BIT32(2) +#define CPSW_MISC_STAT_PEND __BIT32(3) + + if (ISSET(miscstat, CPSW_MISC_HOST_PEND)) { + /* Host Error */ + dmastat = cpsw_read_4(sc, CPSW_CPDMA_DMA_INTSTAT_MASKED); + printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat); + + printf("rxhead %02x\n", sc->sc_rxhead); + + stat = cpsw_read_4(sc, CPSW_CPDMA_DMASTATUS); + printf("CPSW_CPDMA_DMASTATUS %x\n", stat); + stat = cpsw_read_4(sc, CPSW_CPDMA_TX_HDP(0)); + printf("CPSW_CPDMA_TX0_HDP %x\n", stat); + stat = cpsw_read_4(sc, CPSW_CPDMA_TX_CP(0)); + printf("CPSW_CPDMA_TX0_CP %x\n", stat); + stat = cpsw_read_4(sc, CPSW_CPDMA_RX_HDP(0)); + printf("CPSW_CPDMA_RX0_HDP %x\n", stat); + stat = cpsw_read_4(sc, CPSW_CPDMA_RX_CP(0)); + printf("CPSW_CPDMA_RX0_CP %x\n", stat); + + /* Debugger(); */ + + cpsw_write_4(sc, CPSW_CPDMA_DMA_INTMASK_CLEAR, dmastat); + dmastat = cpsw_read_4(sc, CPSW_CPDMA_DMA_INTSTAT_MASKED); + printf("CPSW_CPDMA_DMA_INTSTAT_MASKED %x\n", dmastat); + } + + cpsw_write_4(sc, CPSW_CPDMA_CPDMA_EOI_VECTOR, CPSW_INTROFF_MISC); + + return 1; +} diff --git a/sys/arch/armv7/omap/if_cpswreg.h b/sys/arch/armv7/omap/if_cpswreg.h new file mode 100644 index 00000000000..4df6e42c356 --- /dev/null +++ b/sys/arch/armv7/omap/if_cpswreg.h @@ -0,0 +1,139 @@ +/* $OpenBSD: if_cpswreg.h,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ + +/*- + * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 THE AUTHOR OR CONTRIBUTORS 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. + * + * $FreeBSD$ + */ + +#ifndef _IF_CPSWREG_H +#define _IF_CPSWREG_H + +#define CPSW_SS_OFFSET 0x0000 +#define CPSW_SS_IDVER (CPSW_SS_OFFSET + 0x00) +#define CPSW_SS_SOFT_RESET (CPSW_SS_OFFSET + 0x08) +#define CPSW_SS_STAT_PORT_EN (CPSW_SS_OFFSET + 0x0C) +#define CPSW_SS_PTYPE (CPSW_SS_OFFSET + 0x10) + +#define CPSW_PORT_OFFSET 0x0100 +#define CPSW_PORT_P_TX_PRI_MAP(p) (CPSW_PORT_OFFSET + 0x118 + ((p-1) * 0x100)) +#define CPSW_PORT_P0_CPDMA_TX_PRI_MAP (CPSW_PORT_OFFSET + 0x01C) +#define CPSW_PORT_P0_CPDMA_RX_CH_MAP (CPSW_PORT_OFFSET + 0x020) +#define CPSW_PORT_P_SA_LO(p) (CPSW_PORT_OFFSET + 0x120 + ((p-1) * 0x100)) +#define CPSW_PORT_P_SA_HI(p) (CPSW_PORT_OFFSET + 0x124 + ((p-1) * 0x100)) + +#define CPSW_CPDMA_OFFSET 0x0800 +#define CPSW_CPDMA_TX_CONTROL (CPSW_CPDMA_OFFSET + 0x04) +#define CPSW_CPDMA_TX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x08) +#define CPSW_CPDMA_RX_CONTROL (CPSW_CPDMA_OFFSET + 0x14) +#define CPSW_CPDMA_RX_TEARDOWN (CPSW_CPDMA_OFFSET + 0x18) +#define CPSW_CPDMA_SOFT_RESET (CPSW_CPDMA_OFFSET + 0x1c) +#define CPSW_CPDMA_DMACONTROL (CPSW_CPDMA_OFFSET + 0x20) +#define CPSW_CPDMA_DMASTATUS (CPSW_CPDMA_OFFSET + 0x24) +#define CPSW_CPDMA_RX_BUFFER_OFFSET (CPSW_CPDMA_OFFSET + 0x28) +#define CPSW_CPDMA_TX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0x80) +#define CPSW_CPDMA_TX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0x84) +#define CPSW_CPDMA_TX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0x88) +#define CPSW_CPDMA_TX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0x8C) +#define CPSW_CPDMA_CPDMA_EOI_VECTOR (CPSW_CPDMA_OFFSET + 0x94) +#define CPSW_CPDMA_RX_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xA0) +#define CPSW_CPDMA_RX_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xA4) +#define CPSW_CPDMA_RX_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xA8) +#define CPSW_CPDMA_RX_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xAc) +#define CPSW_CPDMA_DMA_INTSTAT_RAW (CPSW_CPDMA_OFFSET + 0xB0) +#define CPSW_CPDMA_DMA_INTSTAT_MASKED (CPSW_CPDMA_OFFSET + 0xB4) +#define CPSW_CPDMA_DMA_INTMASK_SET (CPSW_CPDMA_OFFSET + 0xB8) +#define CPSW_CPDMA_DMA_INTMASK_CLEAR (CPSW_CPDMA_OFFSET + 0xBC) +#define CPSW_CPDMA_RX_FREEBUFFER(p) (CPSW_CPDMA_OFFSET + 0x0e0 + ((p) * 0x04)) + +#define CPSW_STATS_OFFSET 0x0900 + +#define CPSW_STATERAM_OFFSET 0x0A00 +#define CPSW_CPDMA_TX_HDP(p) (CPSW_STATERAM_OFFSET + 0x00 + ((p) * 0x04)) +#define CPSW_CPDMA_RX_HDP(p) (CPSW_STATERAM_OFFSET + 0x20 + ((p) * 0x04)) +#define CPSW_CPDMA_TX_CP(p) (CPSW_STATERAM_OFFSET + 0x40 + ((p) * 0x04)) +#define CPSW_CPDMA_RX_CP(p) (CPSW_STATERAM_OFFSET + 0x60 + ((p) * 0x04)) + +#define CPSW_CPTS_OFFSET 0x0C00 + +#define CPSW_ALE_OFFSET 0x0D00 +#define CPSW_ALE_CONTROL (CPSW_ALE_OFFSET + 0x08) +#define CPSW_ALE_TBLCTL (CPSW_ALE_OFFSET + 0x20) +#define CPSW_ALE_TBLW2 (CPSW_ALE_OFFSET + 0x34) +#define CPSW_ALE_TBLW1 (CPSW_ALE_OFFSET + 0x38) +#define CPSW_ALE_TBLW0 (CPSW_ALE_OFFSET + 0x3C) +#define CPSW_ALE_PORTCTL(p) (CPSW_ALE_OFFSET + 0x40 + ((p) * 0x04)) + +#define CPSW_SL_OFFSET 0x0D80 +#define CPSW_SL_MACCONTROL(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x04) +#define CPSW_SL_SOFT_RESET(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x0C) +#define CPSW_SL_RX_MAXLEN(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x10) +#define CPSW_SL_RX_PRI_MAP(p) (CPSW_SL_OFFSET + (0x40 * (p)) + 0x24) + +#define MDIO_OFFSET 0x1000 +#define MDIOCONTROL (MDIO_OFFSET + 0x04) +#define MDIOUSERACCESS0 (MDIO_OFFSET + 0x80) +#define MDIOUSERPHYSEL0 (MDIO_OFFSET + 0x84) + +#define CPSW_WR_OFFSET 0x1200 +#define CPSW_WR_SOFT_RESET (CPSW_WR_OFFSET + 0x04) +#define CPSW_WR_CONTROL (CPSW_WR_OFFSET + 0x08) +#define CPSW_WR_INT_CONTROL (CPSW_WR_OFFSET + 0x0c) +#define CPSW_WR_C_RX_THRESH_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x10) +#define CPSW_WR_C_RX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x14) +#define CPSW_WR_C_TX_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x18) +#define CPSW_WR_C_MISC_EN(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x1C) +#define CPSW_WR_C_RX_THRESH_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x40) +#define CPSW_WR_C_RX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x44) +#define CPSW_WR_C_TX_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x48) +#define CPSW_WR_C_MISC_STAT(p) (CPSW_WR_OFFSET + (0x10 * (p)) + 0x4C) + +#define CPSW_CPPI_RAM_OFFSET 0x2000 + +#define CPSW_PRINTF(sc, fmt, args...) printf("%s: " fmt, sc->sc_dev, ##args) + +#define __BIT32(x) ((uint32_t)__BIT(x)) +#define __BITS32(x, y) ((uint32_t)__BITS((x), (y))) + +/* flags for desciptor word 3 */ +#define CPDMA_BD_SOP __BIT32(31) +#define CPDMA_BD_EOP __BIT32(30) +#define CPDMA_BD_OWNER __BIT32(29) +#define CPDMA_BD_EOQ __BIT32(28) +#define CPDMA_BD_TDOWNCMPLT __BIT32(27) +#define CPDMA_BD_PASSCRC __BIT32(26) +#define CPDMA_BD_PKT_ERR_MASK __BITS32(21,20) + +struct cpsw_cpdma_bd { + uint32_t word[4]; +}; + +/* Interrupt offsets */ +#define CPSW_INTROFF_RXTH 0 +#define CPSW_INTROFF_RX 1 +#define CPSW_INTROFF_TX 2 +#define CPSW_INTROFF_MISC 3 + +#endif /*_IF_CPSWREG_H */ diff --git a/sys/arch/armv7/omap/intc.c b/sys/arch/armv7/omap/intc.c new file mode 100644 index 00000000000..2e515a54b16 --- /dev/null +++ b/sys/arch/armv7/omap/intc.c @@ -0,0 +1,423 @@ +/* $OpenBSD: intc.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* + * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/queue.h> +#include <sys/malloc.h> +#include <sys/device.h> +#include <sys/evcount.h> +#include <machine/bus.h> +#include <armv7/omap/omapvar.h> +#include "intc.h" + +#define INTC_NUM_IRQ intc_nirq +#define INTC_NUM_BANKS (intc_nirq/32) +#define INTC_MAX_IRQ 128 +#define INTC_MAX_BANKS (INTC_MAX_IRQ/32) + +/* registers */ +#define INTC_REVISION 0x00 /* R */ +#define INTC_SYSCONFIG 0x10 /* RW */ +#define INTC_SYSCONFIG_AUTOIDLE 0x1 +#define INTC_SYSCONFIG_SOFTRESET 0x2 +#define INTC_SYSSTATUS 0x14 /* R */ +#define INTC_SYSSYSTATUS_RESETDONE 0x1 +#define INTC_SIR_IRQ 0x40 /* R */ +#define INTC_SIR_FIQ 0x44 /* R */ +#define INTC_CONTROL 0x48 /* RW */ +#define INTC_CONTROL_NEWIRQ 0x1 +#define INTC_CONTROL_NEWFIQ 0x2 +#define INTC_CONTROL_GLOBALMASK 0x1 +#define INTC_PROTECTION 0x4c /* RW */ +#define INTC_PROTECTION_PROT 1 /* only privileged mode */ +#define INTC_IDLE 0x50 /* RW */ + +#define INTC_IRQ_TO_REG(i) (((i) >> 5) & 0x3) +#define INTC_IRQ_TO_REGi(i) ((i) & 0x1f) +#define INTC_ITRn(i) 0x80+(0x20*i)+0x00 /* R */ +#define INTC_MIRn(i) 0x80+(0x20*i)+0x04 /* RW */ +#define INTC_CLEARn(i) 0x80+(0x20*i)+0x08 /* RW */ +#define INTC_SETn(i) 0x80+(0x20*i)+0x0c /* RW */ +#define INTC_ISR_SETn(i) 0x80+(0x20*i)+0x10 /* RW */ +#define INTC_ISR_CLEARn(i) 0x80+(0x20*i)+0x14 /* RW */ +#define INTC_PENDING_IRQn(i) 0x80+(0x20*i)+0x18 /* R */ +#define INTC_PENDING_FIQn(i) 0x80+(0x20*i)+0x1c /* R */ + +#define INTC_ILRn(i) 0x100+(4*i) +#define INTC_ILR_IRQ 0x0 /* not of FIQ */ +#define INTC_ILR_FIQ 0x1 +#define INTC_ILR_PRIs(pri) ((pri) << 2) +#define INTC_ILR_PRI(reg) (((reg) >> 2) & 0x2f) +#define INTC_MIN_PRI 63 +#define INTC_STD_PRI 32 +#define INTC_MAX_PRI 0 + +struct intrhand { + TAILQ_ENTRY(intrhand) ih_list; /* link on intrq list */ + int (*ih_func)(void *); /* handler */ + void *ih_arg; /* arg for handler */ + int ih_ipl; /* IPL_* */ + int ih_irq; /* IRQ number */ + struct evcount ih_count; + char *ih_name; +}; + +struct intrq { + TAILQ_HEAD(, intrhand) iq_list; /* handler list */ + int iq_irq; /* IRQ to mask while handling */ + int iq_levels; /* IPL_*'s this IRQ has */ + int iq_ist; /* share type */ +}; + +volatile int softint_pending; + +struct intrq intc_handler[INTC_MAX_IRQ]; +u_int32_t intc_smask[NIPL]; +u_int32_t intc_imask[INTC_MAX_BANKS][NIPL]; + +bus_space_tag_t intc_iot; +bus_space_handle_t intc_ioh; +int intc_nirq; + +void intc_attach(struct device *, struct device *, void *); +int intc_spllower(int new); +int intc_splraise(int new); +void intc_setipl(int new); +void intc_calc_mask(void); + +struct cfattach intc_ca = { + sizeof (struct device), NULL, intc_attach +}; + +struct cfdriver intc_cd = { + NULL, "intc", DV_DULL +}; + +int intc_attached = 0; + +void +intc_attach(struct device *parent, struct device *self, void *args) +{ + struct omap_attach_args *oa = args; + int i; + u_int32_t rev; + + intc_iot = oa->oa_iot; + if (bus_space_map(intc_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &intc_ioh)) + panic("intc_attach: bus_space_map failed!"); + + rev = bus_space_read_4(intc_iot, intc_ioh, INTC_REVISION); + + printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); + + /* software reset of the part? */ + /* set protection bit (kernel only)? */ +#if 0 + bus_space_write_4(intc_iot, intc_ioh, INTC_PROTECTION, + INTC_PROTECTION_PROT); +#endif + + /* enable interface clock power saving mode */ + bus_space_write_4(intc_iot, intc_ioh, INTC_SYSCONFIG, + INTC_SYSCONFIG_AUTOIDLE); + + switch (board_id) { + case BOARD_ID_AM335X_BEAGLEBONE: + intc_nirq = 128; + break; + default: + intc_nirq = 96; + break; + } + + /* mask all interrupts */ + for (i = 0; i < INTC_NUM_BANKS; i++) + bus_space_write_4(intc_iot, intc_ioh, INTC_MIRn(i), 0xffffffff); + + for (i = 0; i < INTC_NUM_IRQ; i++) { + bus_space_write_4(intc_iot, intc_ioh, INTC_ILRn(i), + INTC_ILR_PRIs(INTC_MIN_PRI)|INTC_ILR_IRQ); + + TAILQ_INIT(&intc_handler[i].iq_list); + } + + intc_calc_mask(); + bus_space_write_4(intc_iot, intc_ioh, INTC_CONTROL, + INTC_CONTROL_NEWIRQ); + + intc_attached = 1; + + /* insert self as interrupt handler */ + arm_set_intr_handler(intc_splraise, intc_spllower, intc_splx, + intc_setipl, + intc_intr_establish, intc_intr_disestablish, intc_intr_string, + intc_irq_handler); + + intc_setipl(IPL_HIGH); /* XXX ??? */ + enable_interrupts(I32_bit); +} + +void +intc_calc_mask(void) +{ + struct cpu_info *ci = curcpu(); + int irq; + struct intrhand *ih; + int i; + + for (irq = 0; irq < INTC_NUM_IRQ; irq++) { + int max = IPL_NONE; + int min = IPL_HIGH; + TAILQ_FOREACH(ih, &intc_handler[irq].iq_list, ih_list) { + if (ih->ih_ipl > max) + max = ih->ih_ipl; + + if (ih->ih_ipl < min) + min = ih->ih_ipl; + } + + intc_handler[irq].iq_irq = max; + + if (max == IPL_NONE) + min = IPL_NONE; + +#ifdef DEBUG_INTC + if (min != IPL_NONE) { + printf("irq %d to block at %d %d reg %d bit %d\n", + irq, max, min, INTC_IRQ_TO_REG(irq), + INTC_IRQ_TO_REGi(irq)); + } +#endif + /* Enable interrupts at lower levels, clear -> enable */ + for (i = 0; i < min; i++) + intc_imask[INTC_IRQ_TO_REG(irq)][i] &= + ~(1 << INTC_IRQ_TO_REGi(irq)); + for (; i <= IPL_HIGH; i++) + intc_imask[INTC_IRQ_TO_REG(irq)][i] |= + 1 << INTC_IRQ_TO_REGi(irq); + /* XXX - set enable/disable, priority */ + bus_space_write_4(intc_iot, intc_ioh, INTC_ILRn(irq), + INTC_ILR_PRIs(NIPL-max)|INTC_ILR_IRQ); + } + arm_init_smask(); + intc_setipl(ci->ci_cpl); +} + +void +intc_splx(int new) +{ + struct cpu_info *ci = curcpu(); + intc_setipl(new); + + if (ci->ci_ipending & arm_smask[ci->ci_cpl]) + arm_do_pending_intr(ci->ci_cpl); +} + +int +intc_spllower(int new) +{ + struct cpu_info *ci = curcpu(); + int old = ci->ci_cpl; + intc_splx(new); + return (old); +} + +int +intc_splraise(int new) +{ + struct cpu_info *ci = curcpu(); + int old; + old = ci->ci_cpl; + + /* + * setipl must always be called because there is a race window + * where the variable is updated before the mask is set + * an interrupt occurs in that window without the mask always + * being set, the hardware might not get updated on the next + * splraise completely messing up spl protection. + */ + if (old > new) + new = old; + + intc_setipl(new); + + return (old); +} + +void +intc_setipl(int new) +{ + struct cpu_info *ci = curcpu(); + int i; + int psw; + if (intc_attached == 0) + return; + + psw = disable_interrupts(I32_bit); +#if 0 + { + volatile static int recursed = 0; + if (recursed == 0) { + recursed = 1; + if (new != 12) + printf("setipl %d\n", new); + recursed = 0; + } + } +#endif + ci->ci_cpl = new; + for (i = 0; i < INTC_NUM_BANKS; i++) + bus_space_write_4(intc_iot, intc_ioh, + INTC_MIRn(i), intc_imask[i][new]); + bus_space_write_4(intc_iot, intc_ioh, INTC_CONTROL, + INTC_CONTROL_NEWIRQ); + restore_interrupts(psw); +} + +void +intc_intr_bootstrap(vaddr_t addr) +{ + int i, j; + extern struct bus_space armv7_bs_tag; + intc_iot = &armv7_bs_tag; + intc_ioh = addr; + for (i = 0; i < INTC_NUM_BANKS; i++) + for (j = 0; j < NIPL; j++) + intc_imask[i][j] = 0xffffffff; +} + +void +intc_irq_handler(void *frame) +{ + int irq, pri, s; + struct intrhand *ih; + void *arg; + + irq = bus_space_read_4(intc_iot, intc_ioh, INTC_SIR_IRQ); +#ifdef DEBUG_INTC + printf("irq %d fired\n", irq); +#endif + + pri = intc_handler[irq].iq_irq; + s = intc_splraise(pri); + TAILQ_FOREACH(ih, &intc_handler[irq].iq_list, ih_list) { + if (ih->ih_arg != 0) + arg = ih->ih_arg; + else + arg = frame; + + if (ih->ih_func(arg)) + ih->ih_count.ec_count++; + + } + bus_space_write_4(intc_iot, intc_ioh, INTC_CONTROL, + INTC_CONTROL_NEWIRQ); + + intc_splx(s); +} + +void * +intc_intr_establish(int irqno, int level, int (*func)(void *), + void *arg, char *name) +{ + int psw; + struct intrhand *ih; + + if (irqno < 0 || irqno >= INTC_NUM_IRQ) + panic("intc_intr_establish: bogus irqnumber %d: %s", + irqno, name); + psw = disable_interrupts(I32_bit); + + /* no point in sleeping unless someone can free memory. */ + ih = (struct intrhand *)malloc (sizeof *ih, M_DEVBUF, + cold ? M_NOWAIT : M_WAITOK); + if (ih == NULL) + panic("intr_establish: can't malloc handler info"); + ih->ih_func = func; + ih->ih_arg = arg; + ih->ih_ipl = level; + ih->ih_irq = irqno; + ih->ih_name = name; + + TAILQ_INSERT_TAIL(&intc_handler[irqno].iq_list, ih, ih_list); + + if (name != NULL) + evcount_attach(&ih->ih_count, name, &ih->ih_irq); + +#ifdef DEBUG_INTC + printf("intc_intr_establish irq %d level %d [%s]\n", irqno, level, + name); +#endif + intc_calc_mask(); + + restore_interrupts(psw); + return (ih); +} + +void +intc_intr_disestablish(void *cookie) +{ + int psw; + struct intrhand *ih = cookie; + int irqno = ih->ih_irq; + psw = disable_interrupts(I32_bit); + TAILQ_REMOVE(&intc_handler[irqno].iq_list, ih, ih_list); + if (ih->ih_name != NULL) + evcount_detach(&ih->ih_count); + free(ih, M_DEVBUF); + restore_interrupts(psw); +} + +const char * +intc_intr_string(void *cookie) +{ + return "huh?"; +} + + +#if 0 +int intc_tst(void *a); + +int +intc_tst(void *a) +{ + printf("inct_tst called\n"); + bus_space_write_4(intc_iot, intc_ioh, INTC_ISR_CLEARn(0), 2); + return 1; +} + +void intc_test(void); +void intc_test(void) +{ + void * ih; + printf("about to register handler\n"); + ih = intc_intr_establish(1, IPL_BIO, intc_tst, NULL, "intctst"); + + printf("about to set bit\n"); + bus_space_write_4(intc_iot, intc_ioh, INTC_ISR_SETn(0), 2); + + printf("about to clear bit\n"); + bus_space_write_4(intc_iot, intc_ioh, INTC_ISR_CLEARn(0), 2); + + printf("about to remove handler\n"); + intc_intr_disestablish(ih); + + printf("done\n"); +} +#endif diff --git a/sys/arch/armv7/omap/intc.h b/sys/arch/armv7/omap/intc.h new file mode 100644 index 00000000000..afb54dd41a3 --- /dev/null +++ b/sys/arch/armv7/omap/intc.h @@ -0,0 +1,74 @@ +/* $OpenBSD: intc.h,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* + * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef _OMAPINTC_INTR_H_ +#define _OMAPINTC_INTR_H_ + +#ifndef _LOCORE + +#include <arm/armreg.h> +#include <arm/cpufunc.h> +#include <machine/intr.h> +#include <arm/softintr.h> + +extern __volatile int current_spl_level; +extern __volatile int softint_pending; +void intc_do_pending(void); + +#define SI_TO_IRQBIT(si) (1U<<(si)) +void intc_setipl(int new); +void intc_splx(int new); +int intc_splraise(int ipl); +int intc_spllower(int ipl); +void intc_setsoftintr(int si); + +/* + * An useful function for interrupt handlers. + * XXX: This shouldn't be here. + */ +static __inline int +find_first_bit( uint32_t bits ) +{ + int count; + + /* since CLZ is available only on ARMv5, this isn't portable + * to all ARM CPUs. This file is for OMAPINTC processor. + */ + asm( "clz %0, %1" : "=r" (count) : "r" (bits) ); + return 31-count; +} + + +/* + * This function *MUST* be called very early on in a port's + * initarm() function, before ANY spl*() functions are called. + * + * The parameter is the virtual address of the OMAPINTC's Interrupt + * Controller registers. + */ +void intc_intr_bootstrap(vaddr_t); + +void intc_irq_handler(void *); +void *intc_intr_establish(int irqno, int level, int (*func)(void *), + void *cookie, char *name); +void intc_intr_disestablish(void *cookie); +const char *intc_intr_string(void *cookie); + +#endif /* ! _LOCORE */ + +#endif /* _OMAPINTC_INTR_H_ */ + diff --git a/sys/arch/armv7/omap/omap.c b/sys/arch/armv7/omap/omap.c new file mode 100644 index 00000000000..259176ac212 --- /dev/null +++ b/sys/arch/armv7/omap/omap.c @@ -0,0 +1,232 @@ +/* $OpenBSD: omap.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* + * Copyright (c) 2005,2008 Dale Rahn <drahn@openbsd.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/reboot.h> +#define _ARM32_BUS_DMA_PRIVATE +#include <machine/bus.h> +#include <arch/arm/armv7/armv7var.h> +#include <armv7/omap/omapvar.h> + +struct arm32_bus_dma_tag omap_bus_dma_tag = { + 0, + 0, + NULL, + _bus_dmamap_create, + _bus_dmamap_destroy, + _bus_dmamap_load, + _bus_dmamap_load_mbuf, + _bus_dmamap_load_uio, + _bus_dmamap_load_raw, + _bus_dmamap_unload, + _bus_dmamap_sync, + _bus_dmamem_alloc, + _bus_dmamem_free, + _bus_dmamem_map, + _bus_dmamem_unmap, + _bus_dmamem_mmap, +}; + +struct board_dev { + char *name; + int unit; +}; + +struct board_dev beagleboard_devs[] = { + { "prcm", 0 }, + { "intc", 0 }, + { "gptimer", 0 }, + { "gptimer", 1 }, + { "omdog", 0 }, + { "omgpio", 0 }, + { "omgpio", 1 }, + { "omgpio", 2 }, + { "omgpio", 3 }, + { "omgpio", 4 }, + { "omgpio", 5 }, + { "ommmc", 0 }, /* HSMMC1 */ + { "com", 2 }, /* UART3 */ + { NULL, 0 } +}; + +struct board_dev beaglebone_devs[] = { + { "prcm", 0 }, + { "sitaracm", 0 }, + { "intc", 0 }, + { "dmtimer", 0 }, + { "dmtimer", 1 }, + { "omdog", 0 }, + { "ommmc", 0 }, /* HSMMC0 */ + { "com", 0 }, /* UART0 */ + { "cpsw", 0 }, + { NULL, 0 } +}; + +struct board_dev overo_devs[] = { + { "prcm", 0 }, + { "intc", 0 }, + { "gptimer", 0 }, + { "gptimer", 1 }, + { "omdog", 0 }, + { "omgpio", 0 }, + { "omgpio", 1 }, + { "omgpio", 2 }, + { "omgpio", 3 }, + { "omgpio", 4 }, + { "omgpio", 5 }, + { "ommmc", 0 }, /* HSMMC1 */ + { "com", 2 }, /* UART3 */ + { NULL, 0 } +}; + +struct board_dev pandaboard_devs[] = { + { "omapid", 0 }, + { "prcm", 0 }, + { "omdog", 0 }, + { "omgpio", 0 }, + { "omgpio", 1 }, + { "omgpio", 2 }, + { "omgpio", 3 }, + { "omgpio", 4 }, + { "omgpio", 5 }, + { "ommmc", 0 }, /* HSMMC1 */ + { "com", 2 }, /* UART3 */ + { "ehci", 0 }, + { NULL, 0 } +}; + +struct board_dev *board_devs; + +struct omap_dev *omap_devs = NULL; + +struct omap_softc { + struct device sc_dv; +}; + +int omap_match(struct device *, void *, void *); +void omap_attach(struct device *, struct device *, void *); +int omap_submatch(struct device *, void *, void *); + +struct cfattach omap_ca = { + sizeof(struct omap_softc), omap_match, omap_attach +}; + +struct cfdriver omap_cd = { + NULL, "omap", DV_DULL +}; + +int +omap_match(struct device *parent, void *cfdata, void *aux) +{ + return (1); +} + +void +omap_attach(struct device *parent, struct device *self, void *aux) +{ + struct board_dev *bd; + + switch (board_id) { + case BOARD_ID_OMAP3_BEAGLE: + printf(": BeagleBoard\n"); + omap3_init(); + board_devs = beagleboard_devs; + break; + case BOARD_ID_AM335X_BEAGLEBONE: + printf(": BeagleBone\n"); + am335x_init(); + board_devs = beaglebone_devs; + break; + case BOARD_ID_OMAP3_OVERO: + printf(": Gumstix Overo\n"); + omap3_init(); + board_devs = overo_devs; + break; + case BOARD_ID_OMAP4_PANDA: + printf(": PandaBoard\n"); + omap4_init(); + board_devs = pandaboard_devs; + break; + default: + printf("\n"); + panic("%s: board type 0x%x unknown", __func__, board_id); + } + + /* Directly configure on-board devices (dev* in config file). */ + for (bd = board_devs; bd->name != NULL; bd++) { + struct omap_dev *od = omap_find_dev(bd->name, bd->unit); + struct omap_attach_args oa; + + if (od == NULL) { + printf("%s: device %s unit %d not found\n", + self->dv_xname, bd->name, bd->unit); + continue; + } + + memset(&oa, 0, sizeof(oa)); + oa.oa_dev = od; + oa.oa_iot = &armv7_bs_tag; + oa.oa_dmat = &omap_bus_dma_tag; + + if (config_found_sm(self, &oa, NULL, omap_submatch) == NULL) + printf("%s: device %s unit %d not configured\n", + self->dv_xname, bd->name, bd->unit); + } +} + +/* + * We do direct configuration of devices on this SoC "bus", so we + * never call the child device's match function at all (it can be + * NULL in the struct cfattach). + */ +int +omap_submatch(struct device *parent, void *child, void *aux) +{ + struct cfdata *cf = child; + struct omap_attach_args *oa = aux; + + if (strcmp(cf->cf_driver->cd_name, oa->oa_dev->name) == 0) + return (1); + + /* "These are not the droids you are looking for." */ + return (0); +} + +void +omap_set_devs(struct omap_dev *devs) +{ + omap_devs = devs; +} + +struct omap_dev * +omap_find_dev(const char *name, int unit) +{ + struct omap_dev *od; + + if (omap_devs == NULL) + panic("%s: omap_devs == NULL", __func__); + + for (od = omap_devs; od->name != NULL; od++) { + if (od->unit == unit && strcmp(od->name, name) == 0) + return (od); + } + + return (NULL); +} diff --git a/sys/arch/armv7/omap/omap3.c b/sys/arch/armv7/omap/omap3.c new file mode 100644 index 00000000000..913770fff24 --- /dev/null +++ b/sys/arch/armv7/omap/omap3.c @@ -0,0 +1,196 @@ +/* $OpenBSD: omap3.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ + +/* + * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/types.h> +#include <sys/param.h> + +#include <machine/bus.h> + +#include <armv7/omap/omapvar.h> + +#define PRCM_ADDR 0x48004000 +#define PRCM_SIZE 0x2000 + +#define INTC_ADDR 0x48200000 +#define INTC_SIZE 0x200 + +#define GPTIMERx_SIZE 0x100 +#define GPTIMER1_ADDR 0x48318000 +#define GPTIMER1_IRQ 37 +#define GPTIMER2_ADDR 0x49032000 +#define GPTIMER2_IRQ 38 + +#define WD_ADDR 0x48314000 +#define WD_SIZE 0x80 + +#define GPIOx_SIZE 0x1000 +#define GPIO1_ADDR 0x48310000 +#define GPIO2_ADDR 0x49050000 +#define GPIO3_ADDR 0x49052000 +#define GPIO4_ADDR 0x49054000 +#define GPIO5_ADDR 0x49056000 +#define GPIO6_ADDR 0x49058000 + +#define GPIO1_IRQ 29 +#define GPIO2_IRQ 30 +#define GPIO3_IRQ 31 +#define GPIO4_IRQ 32 +#define GPIO5_IRQ 33 +#define GPIO6_IRQ 34 + +#define UARTx_SIZE 0x400 +#define UART1_ADDR 0x4806A000 +#define UART2_ADDR 0x4806C000 +#define UART3_ADDR 0x49020000 + +#define UART1_IRQ 72 +#define UART2_IRQ 73 +#define UART3_IRQ 74 + +#define HSMMCx_SIZE 0x200 +#define HSMMC1_ADDR 0x4809c000 +#define HSMMC1_IRQ 83 + +#define USBTLL_ADDR 0x48062000 +#define USBTLL_SIZE 0x1000 + +struct omap_dev omap3_devs[] = { + + /* + * Power, Reset and Clock Manager + */ + + { .name = "prcm", + .unit = 0, + .mem = { { PRCM_ADDR, PRCM_SIZE } }, + }, + + /* + * Interrupt Controller + */ + + { .name = "intc", + .unit = 0, + .mem = { { INTC_ADDR, INTC_SIZE } }, + }, + + /* + * General Purpose Timers + */ + + { .name = "gptimer", + .unit = 1, /* XXX see gptimer.c */ + .mem = { { GPTIMER1_ADDR, GPTIMERx_SIZE } }, + .irq = { GPTIMER1_IRQ } + }, + + { .name = "gptimer", + .unit = 0, /* XXX see gptimer.c */ + .mem = { { GPTIMER2_ADDR, GPTIMERx_SIZE } }, + .irq = { GPTIMER2_IRQ } + }, + + /* + * GPIO + */ + + { .name = "omgpio", + .unit = 0, + .mem = { { GPIO1_ADDR, GPIOx_SIZE } }, + .irq = { GPIO1_IRQ } + }, + + { .name = "omgpio", + .unit = 1, + .mem = { { GPIO2_ADDR, GPIOx_SIZE } }, + .irq = { GPIO2_IRQ } + }, + + { .name = "omgpio", + .unit = 2, + .mem = { { GPIO3_ADDR, GPIOx_SIZE } }, + .irq = { GPIO3_IRQ } + }, + + { .name = "omgpio", + .unit = 3, + .mem = { { GPIO4_ADDR, GPIOx_SIZE } }, + .irq = { GPIO4_IRQ } + }, + + { .name = "omgpio", + .unit = 4, + .mem = { { GPIO5_ADDR, GPIOx_SIZE } }, + .irq = { GPIO5_IRQ } + }, + + { .name = "omgpio", + .unit = 5, + .mem = { { GPIO6_ADDR, GPIOx_SIZE } }, + .irq = { GPIO6_IRQ } + }, + + /* + * Watchdog Timer + */ + + { .name = "omdog", + .unit = 0, + .mem = { { WD_ADDR, WD_SIZE } } + }, + + /* + * UART + */ + + { .name = "com", + .unit = 2, + .mem = { { UART3_ADDR, UARTx_SIZE } }, + .irq = { UART3_IRQ } + }, + + /* + * MMC + */ + + { .name = "ommmc", + .unit = 0, + .mem = { { HSMMC1_ADDR, HSMMCx_SIZE } }, + .irq = { HSMMC1_IRQ } + }, + + /* + * USB + */ + + { .name = "omusbtll", + .unit = 0, + .mem = { { USBTLL_ADDR, USBTLL_SIZE } }, + }, + + /* Terminator */ + { .name = NULL, + .unit = 0, + } +}; + +void +omap3_init(void) +{ + omap_set_devs(omap3_devs); +} diff --git a/sys/arch/armv7/omap/omap3_prcmreg.h b/sys/arch/armv7/omap/omap3_prcmreg.h new file mode 100644 index 00000000000..3d41d170655 --- /dev/null +++ b/sys/arch/armv7/omap/omap3_prcmreg.h @@ -0,0 +1,197 @@ +/* $OpenBSD: omap3_prcmreg.h,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* + * Copyright (c) 2007, 2009, 2012 Dale Rahn <drahn@dalerahn.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* XXX - verify these definitions and correctly merge them with omap4 */ +#define CM_FCLKEN_IVA2 0x0000 +#define CM_CLKEN_PLL_IVA2 0x0004 +#define CM_IDLEST_IVA2 0x0020 +#define CM_IDLEST_PLL_IVA2 0x0024 +#define CM_AUTOIDLE_PLL_IVA2 0x0034 +#define CM_CLKSEL1_PLL_IVA2 0x0040 +#define CM_CLKSEL2_PLL_IVA2 0x0044 +#define CM_CLKSTCTRL_IVA2 0x0048 +#define CM_CLKSTST_IVA2 0x004c + +#define CM_CLKSEL_MPU 0x0940 +#define CM_CLKSTCTRL_MPU 0x0948 +#define RM_RSTST_MPU 0x0958 +#define PM_WKDEP_MPU 0x09C8 +#define PM_EVGENCTRL_MPU 0x09D4 +#define PM_EVEGENONTIM_MPU 0x09D8 +#define PM_EVEGENOFFTIM_MPU 0x09DC +#define PM_PWSTCTRL_MPU 0x09E0 +#define PM_PWSTST_MPU 0x09E4 + +#define CM_ICLKEN1_CORE 0x0a10 +#define CM_ICLKEN1_CORE_MSK 0x7ffffed2 +#define CM_ICLKEN2_CORE 0x0a14 +#define CM_ICLKEN2_CORE_MSK 0x0000001f +#define CM_ICLKEN3_CORE 0x0a18 +#define CM_ICLKEN3_CORE_MSK 0x00000004 +#define CM_ICLKEN4_CORE 0x0a1C +#define CM_IDLEST1_CORE 0x0a20 +#define CM_IDLEST2_CORE 0x0a24 +#define CM_IDLEST4_CORE 0x0a2C +#define CM_AUTOIDLE1_CORE 0x0a30 +#define CM_AUTOIDLE2_CORE 0x0a34 +#define CM_AUTOIDLE3_CORE 0x0a38 +#define CM_AUTOIDLE4_CORE 0x0a3C +#define CM_CLKSEL1_CORE 0x0a40 +#define CM_CLKSEL2_CORE 0x0a44 +#define CM_CLKSTCTRL_CORE 0x0a48 +#define PM_WKEN1_CORE 0x0aA0 +#define PM_WKEN2_CORE 0x0aA4 +#define PM_WKST1_CORE 0x0aB0 +#define PM_WKST2_CORE 0x0aB4 +#define PM_WKDEP_CORE 0x0aC8 +#define PM_PWSTCTRL_CORE 0x0aE0 +#define PM_PWSTST_CORE 0x0aE4 +#define CM_FCLKEN_GFX 0x0b00 +#define CM_ICLKEN_GFX 0x0b10 + +#define CM_IDLEST_GFX 0x0b20 +#define CM_CLKSEL_GFX 0x0b40 +#define CM_CLKSTCTRL_GFX 0x0b48 +#define RM_RSTCTRL_GFX 0x0b50 +#define RM_RSTST_GFX 0x0b58 +#define PM_WKDEP_GFX 0x0bC8 +#define PM_PWSTCTRL_GFX 0x0bE0 +#define PM_PWSTST_GFX 0x0bE4 +#define CM_FCLKEN_WKUP 0x0c00 +#define CM_FCLKEN_WKUP_GPT1 1 +#define CM_FCLKEN_WKUP_GPIOS 4 +#define CM_FCLKEN_WKUP_MPU_WDT 8 +#define CM_ICLKEN_WKUP 0xc10 +#define CM_ICLKEN_WKUP_GPT1 0x01 +#define CM_ICLKEN_WKUP_32KSYNC 0x02 +#define CM_ICLKEN_WKUP_GPIOS 0x04 +#define CM_ICLKEN_WKUP_MPU_WDT 0x08 +#define CM_ICLKEN_WKUP_WDT1 0x10 +#define CM_ICLKEN_WKUP_OMAPCTRL 0x20 +#define CM_IDLEST_WKUP 0x0c20 +#define CM_AUTOIDLE_WKUP 0x0c30 +#define CM_CLKSEL_WKUP 0x0c40 +#define RM_RSTCTRL_WKUP 0x0c50 +#define RM_RSTTIME_WKUP 0x0c54 +#define RM_RSTST_WKUP 0x0c58 +#define PM_WKEN_WKUP 0x0cA0 +#define PM_WKST_WKUP 0x0cB0 +#define CM_CLKEN_PLL 0x0d00 +#define CM_CLKEN2_PLL 0x0d04 +#define CM_IDLEST_CKGEN 0x0d20 +#define CM_AUTOIDLE_PLL 0x0d30 +#define CM_AUTOIDLE2_PLL 0x0d34 +#define CM_CLKSEL1_PLL 0x0d40 +#define CM_CLKSEL2_PLL 0x0d44 +#define CM_CLKSEL3_PLL 0x0d48 +#define CM_CLKSEL4_PLL 0x0d4C +#define CM_CLKSEL5_PLL 0x0d50 +#define CM_FCLKEN_PER 0x1000 +#define CM_ICLKEN_PER 0x1010 +#define CM_IDLEST_PER 0x1020 +#define CM_AUTOIDLE_PER 0x1030 +#define CM_CLKSEL_PER 0x1040 +#define CM_SLEEPDEP_PER 0x1044 +#define CM_CLKSTCTRL_PER 0x1048 +#define CM_CLKSTST_PER 0x104C + +#define CM_CLKSEL1_EMU 0x5140 +#define CM_CLKSTCTRL_EMU 0x5148 +#define CM_CLKSTST_EMU 0x514C +#define CM_CLKSEL2_EMU 0x5150 +#define CM_CLKSEL3_EMU 0x5154 + +#define CM_POLCTRL 0x529C + +#define CM_IDLEST_NEON 0x5320 +#define CM_CLKSTCTRL_NEON 0x5348 + +#define CM_FCLKEN_USBHOST 0x5400 +#define CM_ICLKEN_USBHOST 0x5410 +#define CM_IDLEST_USBHOST 0x5420 +#define CM_AUTOIDLE_USBHOST 0x5430 +#define CM_SLEEPDEP_USBHOST 0x5444 +#define CM_CLKSTCTRL_USBHOST 0x5448 +#define CM_CLKSTST_USBHOST 0x544C + +/* from prcmvar.h */ +#define CM_FCLKEN1_CORE 0x0a00 +#define CM_FCLKEN1_CORE_MSK 0x41fffe00 +#define CM_FCLKEN2_CORE 0x0a04 +#define CM_FCLKEN2_CORE_MSK 0x00000000 +#define CM_FCLKEN3_CORE 0x0a08 +#define CM_FCLKEN3_CORE_MSK 0x00000007 + +#define PRCM_REG_CORE_CLK1 0 +#define PRCM_REG_CORE_CLK1_FADDR CM_FCLKEN1_CORE +#define PRCM_REG_CORE_CLK1_IADDR CM_ICLKEN1_CORE +#define PRCM_REG_CORE_CLK1_FMASK CM_FCLKEN1_CORE_MSK +#define PRCM_REG_CORE_CLK1_IMASK CM_ICLKEN1_CORE_MSK +#define PRCM_REG_CORE_CLK1_BASE (PRCM_REG_CORE_CLK1*32) +#define PRCM_CLK_EN_MMC3 (PRCM_REG_CORE_CLK1_BASE + 30) +#define PRCM_CLK_EN_ICR (PRCM_REG_CORE_CLK1_BASE + 29) +#define PRCM_CLK_EN_AES2 (PRCM_REG_CORE_CLK1_BASE + 28) +#define PRCM_CLK_EN_SHA12 (PRCM_REG_CORE_CLK1_BASE + 27) +#define PRCM_CLK_EN_DES2 (PRCM_REG_CORE_CLK1_BASE + 26) +#define PRCM_CLK_EN_MMC2 (PRCM_REG_CORE_CLK1_BASE + 25) +#define PRCM_CLK_EN_MMC1 (PRCM_REG_CORE_CLK1_BASE + 24) +#define PRCM_CLK_EN_MSPRO (PRCM_REG_CORE_CLK1_BASE + 23) +#define PRCM_CLK_EN_HDQ (PRCM_REG_CORE_CLK1_BASE + 22) +#define PRCM_CLK_EN_MCSPI4 (PRCM_REG_CORE_CLK1_BASE + 21) +#define PRCM_CLK_EN_MCSPI3 (PRCM_REG_CORE_CLK1_BASE + 20) +#define PRCM_CLK_EN_MCSPI2 (PRCM_REG_CORE_CLK1_BASE + 19) +#define PRCM_CLK_EN_MCSPI1 (PRCM_REG_CORE_CLK1_BASE + 18) +#define PRCM_CLK_EN_I2C3 (PRCM_REG_CORE_CLK1_BASE + 17) +#define PRCM_CLK_EN_I2C2 (PRCM_REG_CORE_CLK1_BASE + 16) +#define PRCM_CLK_EN_I2C1 (PRCM_REG_CORE_CLK1_BASE + 15) +#define PRCM_CLK_EN_UART2 (PRCM_REG_CORE_CLK1_BASE + 14) +#define PRCM_CLK_EN_UART1 (PRCM_REG_CORE_CLK1_BASE + 13) +#define PRCM_CLK_EN_GPT11 (PRCM_REG_CORE_CLK1_BASE + 12) +#define PRCM_CLK_EN_GPT10 (PRCM_REG_CORE_CLK1_BASE + 11) +#define PRCM_CLK_EN_MCBSP5 (PRCM_REG_CORE_CLK1_BASE + 10) +#define PRCM_CLK_EN_MCBSP1 (PRCM_REG_CORE_CLK1_BASE + 9) +#define PRCM_CLK_EN_MAILBOXES (PRCM_REG_CORE_CLK1_BASE + 7) +#define PRCM_CLK_EN_OMAPCTRL (PRCM_REG_CORE_CLK1_BASE + 6) +#define PRCM_CLK_EN_HSOTGUSB (PRCM_REG_CORE_CLK1_BASE + 4) +#define PRCM_CLK_EN_SDRC (PRCM_REG_CORE_CLK1_BASE + 1) + +#define PRCM_REG_CORE_CLK2 1 +#define PRCM_REG_CORE_CLK2_FADDR CM_FCLKEN2_CORE +#define PRCM_REG_CORE_CLK2_IADDR CM_ICLKEN2_CORE +#define PRCM_REG_CORE_CLK2_FMASK CM_FCLKEN2_CORE_MSK +#define PRCM_REG_CORE_CLK2_IMASK CM_ICLKEN2_CORE_MSK +#define PRCM_REG_CORE_CLK2_BASE (PRCM_REG_CORE_CLK2*32) + +#define PRCM_REG_CORE_CLK3 2 +#define PRCM_REG_CORE_CLK3_FADDR CM_FCLKEN3_CORE +#define PRCM_REG_CORE_CLK3_IADDR CM_ICLKEN3_CORE +#define PRCM_REG_CORE_CLK3_FMASK CM_FCLKEN3_CORE_MSK +#define PRCM_REG_CORE_CLK3_IMASK CM_ICLKEN3_CORE_MSK +#define PRCM_REG_CORE_CLK3_BASE (PRCM_REG_CORE_CLK3*32) + +#define CM_CORE_EN_USBTLL (PRCM_REG_CORE_CLK3_BASE + 2) +#define CM_CORE_EN_TS (PRCM_REG_CORE_CLK3_BASE + 1) +#define CM_CORE_EN_CPEFUSE (PRCM_REG_CORE_CLK3_BASE + 0) + +#define PRCM_REG_USBHOST 3 +#define PRCM_REG_USBHOST_FADDR 0x1400 +#define PRCM_REG_USBHOST_IADDR 0x1410 +#define PRCM_REG_USBHOST_FMASK 0x3 +#define PRCM_REG_USBHOST_IMASK 0x1 +#define PRCM_REG_USBHOST_BASE (PRCM_REG_USBHOST*32) + +#define PRCM_CLK_EN_USB (PRCM_REG_USBHOST_BASE + 0) diff --git a/sys/arch/armv7/omap/omap4.c b/sys/arch/armv7/omap/omap4.c new file mode 100644 index 00000000000..3ba281127e3 --- /dev/null +++ b/sys/arch/armv7/omap/omap4.c @@ -0,0 +1,200 @@ +/* $OpenBSD: omap4.c,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ + +/* + * Copyright (c) 2011 Uwe Stuehler <uwe@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <machine/bus.h> +#include <arch/arm/armv7/armv7var.h> + +#include <armv7/omap/omapvar.h> + +#define OMAPID_ADDR 0x4a002000 +#define OMAPID_SIZE 0x1000 + +#define WD_ADDR 0x4a314000 +#define WD_SIZE 0x80 + +#define GPIOx_SIZE 0x1000 +#define GPIO1_ADDR 0x4a310000 +#define GPIO2_ADDR 0x48055000 +#define GPIO3_ADDR 0x48057000 +#define GPIO4_ADDR 0x48059000 +#define GPIO5_ADDR 0x4805b000 +#define GPIO6_ADDR 0x4805d000 + +#define GPIO1_IRQ 29 +#define GPIO2_IRQ 30 +#define GPIO3_IRQ 31 +#define GPIO4_IRQ 32 +#define GPIO5_IRQ 33 +#define GPIO6_IRQ 34 + +#define UARTx_SIZE 0x400 +#define UART1_ADDR 0x4806A000 +#define UART2_ADDR 0x4806C000 +#define UART3_ADDR 0x48020000 +#define UART4_ADDR 0x4806E000 + +#define UART1_IRQ 72 +#define UART2_IRQ 73 +#define UART3_IRQ 74 +#define UART4_IRQ 70 + +#define HSMMCx_SIZE 0x300 +#define HSMMC1_ADDR 0x4809c000 +#define HSMMC1_IRQ 83 + +#define PRM_ADDR 0x4a306000 +#define PRM_SIZE 0x2000 +#define CM1_ADDR 0x4a004000 +#define CM1_SIZE 0x1000 +#define CM2_ADDR 0x4a008000 +#define CM2_SIZE 0x2000 +#define SCRM_ADDR 0x4a30a000 +#define SCRM_SIZE 0x1000 +#define PCNF1_ADDR 0x4a100000 +#define PCNF1_SIZE 0x1000 +#define PCNF2_ADDR 0x4a31e000 +#define PCNF2_SIZE 0x1000 + +#define HSUSBHOST_ADDR 0x4a064000 +#define HSUSBHOST_SIZE 0x800 +#define USBEHCI_ADDR 0x4a064c00 +#define USBEHCI_SIZE 0x400 +#define USBOHCI_ADDR 0x4a064800 +#define USBOHCI_SIZE 0x400 +#define USBEHCI_IRQ 77 + +struct omap_dev omap4_devs[] = { + + /* + * Power, Reset and Clock Manager + */ + + { .name = "prcm", + .unit = 0, + .mem = { + { PRM_ADDR, PRM_SIZE }, + { CM1_ADDR, CM1_SIZE }, + { CM2_ADDR, CM2_SIZE }, + }, + }, + + /* + * OMAP identification registers/fuses + */ + + { .name = "omapid", + .unit = 0, + .mem = { { OMAPID_ADDR, OMAPID_SIZE } }, + }, + + /* + * GPIO + */ + + { .name = "omgpio", + .unit = 0, + .mem = { { GPIO1_ADDR, GPIOx_SIZE } }, + .irq = { GPIO1_IRQ } + }, + + { .name = "omgpio", + .unit = 1, + .mem = { { GPIO2_ADDR, GPIOx_SIZE } }, + .irq = { GPIO2_IRQ } + }, + + { .name = "omgpio", + .unit = 2, + .mem = { { GPIO3_ADDR, GPIOx_SIZE } }, + .irq = { GPIO3_IRQ } + }, + + { .name = "omgpio", + .unit = 3, + .mem = { { GPIO4_ADDR, GPIOx_SIZE } }, + .irq = { GPIO4_IRQ } + }, + + { .name = "omgpio", + .unit = 4, + .mem = { { GPIO5_ADDR, GPIOx_SIZE } }, + .irq = { GPIO5_IRQ } + }, + + { .name = "omgpio", + .unit = 5, + .mem = { { GPIO6_ADDR, GPIOx_SIZE } }, + .irq = { GPIO6_IRQ } + }, + + /* + * Watchdog Timer + */ + + { .name = "omdog", + .unit = 0, + .mem = { { WD_ADDR, WD_SIZE } } + }, + + /* + * UART + */ + + { .name = "com", + .unit = 2, + .mem = { { UART3_ADDR, UARTx_SIZE } }, + .irq = { UART3_IRQ } + }, + + /* + * MMC + */ + + { .name = "ommmc", + .unit = 0, + .mem = { { HSMMC1_ADDR, HSMMCx_SIZE } }, + .irq = { HSMMC1_IRQ } + }, + + /* + * USB + */ + + { .name = "ehci", + .unit = 0, + .mem = { + { USBEHCI_ADDR, USBEHCI_SIZE }, + { HSUSBHOST_ADDR, HSUSBHOST_SIZE }, + }, + .irq = { USBEHCI_IRQ } + }, + + /* Terminator */ + { .name = NULL, + .unit = 0, + } +}; + +void +omap4_init(void) +{ + omap_set_devs(omap4_devs); +} diff --git a/sys/arch/armv7/omap/omap4_prcmreg.h b/sys/arch/armv7/omap/omap4_prcmreg.h new file mode 100644 index 00000000000..9cff537f1ab --- /dev/null +++ b/sys/arch/armv7/omap/omap4_prcmreg.h @@ -0,0 +1,27 @@ +/* $OpenBSD: omap4_prcmreg.h,v 1.1 2013/09/04 14:38:30 patrick Exp $ */ +/* + * Copyright (c) 2007, 2009, 2012 Dale Rahn <drahn@dalerahn.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#define O4_L3INIT_CM2_OFFSET 0x00001300 +#define O4_CLKCTRL_MODULEMODE_MASK 0x00000003 +#define O4_CLKCTRL_MODULEMODE_DISABLE 0x00000000 +#define O4_CLKCTRL_MODULEMODE_AUTO 0x00000001 +#define O4_CLKCTRL_MODULEMODE_ENABLE 0x00000001 + +#define O4_MAX_MODULE_ENABLE_WAIT 1000 + +#define O4_CLKCTRL_IDLEST_MASK 0x00030000UL +#define O4_CLKCTRL_IDLEST_ENABLED 0x00000000UL diff --git a/sys/arch/armv7/omap/omap_com.c b/sys/arch/armv7/omap/omap_com.c new file mode 100644 index 00000000000..8700000d6a5 --- /dev/null +++ b/sys/arch/armv7/omap/omap_com.c @@ -0,0 +1,112 @@ +/* $OpenBSD: omap_com.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ +/* + * Copyright 2003 Wasabi Systems, Inc. + * All rights reserved. + * + * Written by Steve C. Woodford 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/tty.h> + +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/ic/comreg.h> +#include <dev/ic/comvar.h> + +/* pick up armv7_a4x_bs_tag */ +#include <arch/arm/armv7/armv7var.h> + +#include <armv7/omap/omapvar.h> + +#define com_isr 8 +#define ISR_RECV (ISR_RXPL | ISR_XMODE | ISR_RCVEIR) + +void omapuart_attach(struct device *, struct device *, void *); +int omapuart_activate(struct device *, int); + +struct cfattach com_omap_ca = { + sizeof (struct com_softc), NULL, omapuart_attach, NULL, + omapuart_activate +}; + +void +omapuart_attach(struct device *parent, struct device *self, void *aux) +{ + struct com_softc *sc = (struct com_softc *)self; + struct omap_attach_args *oa = aux; + + sc->sc_iot = &armv7_a4x_bs_tag; /* XXX: This sucks */ + sc->sc_iobase = oa->oa_dev->mem[0].addr; + sc->sc_frequency = 48000000; + sc->sc_uarttype = COM_UART_TI16750; + + if (bus_space_map(sc->sc_iot, sc->sc_iobase, + oa->oa_dev->mem[0].size, 0, &sc->sc_ioh)) { + printf("%s: bus_space_map failed\n", __func__); + return; + } + + com_attach_subr(sc); + + (void)arm_intr_establish(oa->oa_dev->irq[0], IPL_TTY, comintr, + sc, sc->sc_dev.dv_xname); +} + +int +omapuart_activate(struct device *self, int act) +{ + struct com_softc *sc = (struct com_softc *)self; + bus_space_tag_t iot = sc->sc_iot; + bus_space_handle_t ioh = sc->sc_ioh; + struct tty *tp = sc->sc_tty; + + switch (act) { + case DVACT_SUSPEND: + break; + case DVACT_RESUME: + if (sc->enabled) { + sc->sc_initialize = 1; + comparam(tp, &tp->t_termios); + bus_space_write_1(iot, ioh, com_ier, sc->sc_ier); + + if (ISSET(sc->sc_hwflags, COM_HW_SIR)) { + bus_space_write_1(iot, ioh, com_isr, + ISR_RECV); + } + } + break; + } + return 0; +} diff --git a/sys/arch/armv7/omap/omapid.c b/sys/arch/armv7/omap/omapid.c new file mode 100644 index 00000000000..23c5245d5b9 --- /dev/null +++ b/sys/arch/armv7/omap/omapid.c @@ -0,0 +1,101 @@ +/* $OpenBSD: omapid.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ +/* + * Copyright (c) 2013 Dale Rahn <drahn@dalerahn.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/queue.h> +#include <sys/malloc.h> +#include <sys/device.h> +#include <sys/evcount.h> +#include <sys/socket.h> +#include <sys/timeout.h> +#include <machine/intr.h> +#include <machine/bus.h> +#include <armv7/omap/omapvar.h> + +/* registers */ +#define O4_ID_SIZE 0x1000 +#define O4_FUSE_ID0 0x200 +#define O4_ID_CODE 0x204 +#define O4_FUSE_ID1 0x208 +#define O4_FUSE_ID2 0x20C +#define O4_FUSE_ID3 0x210 +#define O4_FUSE_PRODID0 0x214 +#define O4_FUSE_PRODID1 0x218 + + +struct omapid_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +struct omapid_softc *omapid_sc; + + +void omapid_attach(struct device *parent, struct device *self, void *args); +void omapid_wpending(int flags); + +struct cfattach omapid_ca = { + sizeof (struct omapid_softc), NULL, omapid_attach +}; + +struct cfdriver omapid_cd = { + NULL, "omapid", DV_DULL +}; + +void amptimer_set_clockrate(int32_t new_frequency); /* XXX */ + +void +omapid_attach(struct device *parent, struct device *self, void *args) +{ + struct omap_attach_args *oa = args; + struct omapid_softc *sc = (struct omapid_softc *) self; + uint32_t rev; + uint32_t newclockrate = 0; + char *board; + + sc->sc_iot = oa->oa_iot; + if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &sc->sc_ioh)) + panic("omapid: bus_space_map failed!"); + + omapid_sc = sc; + + board = "unknown"; + switch (board_id) { + case BOARD_ID_OMAP4_PANDA: + rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, O4_ID_CODE); + switch ((rev >> 12) & 0xffff) { + case 0xB852: + case 0xB95C: + board = "omap4430"; + newclockrate = 400 * 1000 * 1000; + break; + case 0xB94E: + board = "omap4460"; + newclockrate = 350 * 1000 * 1000; + break; + } + break; + default: + break; + } + printf(": %s\n", board); + if (newclockrate != 0) + amptimer_set_clockrate(newclockrate); +} diff --git a/sys/arch/armv7/omap/omapvar.h b/sys/arch/armv7/omap/omapvar.h new file mode 100644 index 00000000000..b2a2e565f5e --- /dev/null +++ b/sys/arch/armv7/omap/omapvar.h @@ -0,0 +1,58 @@ +/* $OpenBSD: omapvar.h,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ +/* + * Copyright (c) 2005,2008 Dale Rahn <drahn@drahn.com> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Physical memory range for on-chip devices. */ +struct omap_mem { + u_int32_t addr; /* physical start address */ + u_int32_t size; /* size of range in bytes */ +}; + +#define OMAP_DEV_NMEM 4 /* number of memory ranges */ +#define OMAP_DEV_NIRQ 4 /* number of IRQs per device */ + +/* Descriptor for all on-chip devices. */ +struct omap_dev { + char *name; /* driver name or made up name */ + int unit; /* driver instance number or -1 */ + struct omap_mem mem[OMAP_DEV_NMEM]; /* memory ranges */ + int irq[OMAP_DEV_NIRQ]; /* IRQ number(s) */ +}; + +/* Passed as third arg to attach functions. */ +struct omap_attach_args { + struct omap_dev *oa_dev; + bus_space_tag_t oa_iot; + bus_dma_tag_t oa_dmat; +}; + +void omap_set_devs(struct omap_dev *); +struct omap_dev *omap_find_dev(const char *, int); + +void omap3_init(void); +void omap4_init(void); +void am335x_init(void); + +/* XXX */ +void *avic_intr_establish(int irqno, int level, int (*func)(void *), + void *arg, char *name); + +/* board identification - from uboot */ +#define BOARD_ID_AM335X_BEAGLEBONE 3589 +#define BOARD_ID_OMAP3_BEAGLE 1546 +#define BOARD_ID_OMAP3_OVERO 1798 +#define BOARD_ID_OMAP4_PANDA 2791 +extern uint32_t board_id; diff --git a/sys/arch/armv7/omap/omdisplay.c b/sys/arch/armv7/omap/omdisplay.c new file mode 100644 index 00000000000..4e5cea513c5 --- /dev/null +++ b/sys/arch/armv7/omap/omdisplay.c @@ -0,0 +1,1370 @@ +/* $OpenBSD: omdisplay.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ +/* + * Copyright (c) 2007 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/queue.h> +#include <sys/malloc.h> +#include <sys/device.h> +#include <sys/evcount.h> +#include <sys/conf.h> +#include <sys/uio.h> +#include <machine/bus.h> +#include <armv7/omap/omapvar.h> +#include <armv7/omap/omgpiovar.h> + +#include <dev/cons.h> +#include <dev/wscons/wsconsio.h> +#include <dev/wscons/wsdisplayvar.h> +#include <dev/wscons/wscons_callbacks.h> + +#include <dev/rasops/rasops.h> + +#include "splash16.h" + +#define OMDISPLAY_SIZE 0x1000 +/* registers */ +/* DSS */ +#define DSS_REVISIONNUMBER 0x00 +#define DSS_CONTROL 0x40 +#define DSS_PSA_LCD_REG_1 0x50 +#define DSS_PSA_LCD_REG_2 0x54 +#define DSS_PSA_VIDEO_REG 0x58 +#define DSS_STATUS 0x5C + +/* DCR */ +#define DISPC_REVISION 0x0000 +#define DISPC_SYSCONFIG 0x0010 +#define DISPC_SYSCONFIG_AUTOIDLE 0x00000001 +#define DISPC_SYSCONFIG_SOFTRESET 0x00000002 +#define DISPC_SYSCONFIG_SIDLEMODE_FORCE 0x00000000 +#define DISPC_SYSCONFIG_SIDLEMODE_NONE 0x00000008 +#define DISPC_SYSCONFIG_SIDLEMODE_SMART 0x00000010 +#define DISPC_SYSCONFIG_MIDLEMODE_FORCE 0x00000000 +#define DISPC_SYSCONFIG_MIDLEMODE_NONE 0x00001000 +#define DISPC_SYSCONFIG_MIDLEMODE_SMART 0x00002000 +#define DISPC_SYSSTATUS 0x0014 +#define DISPC_SYSTATUS_RESETDONE 0x00000001 +#define DISPC_IRQSTATUS 0x0018 +#define DISPC_IRQSTATUS_FRAMEDONE 0x00000001 +#define DISPC_IRQSTATUS_VSYNC 0x00000002 +#define DISPC_IRQSTATUS_EVSYNCEVEN 0x00000004 +#define DISPC_IRQSTATUS_EVSYNCODD 0x00000008 +#define DISPC_IRQSTATUS_ACBIASCOUNT 0x00000010 +#define DISPC_IRQSTATUS_PROGLINENUM 0x00000020 +#define DISPC_IRQSTATUS_GFXFIFOUNDER 0x00000040 +#define DISPC_IRQSTATUS_GFXENDWINDOW 0x00000080 +#define DISPC_IRQSTATUS_PALGAMMA 0x00000100 +#define DISPC_IRQSTATUS_OCPERROR 0x00000200 +#define DISPC_IRQSTATUS_VID1FIFOUNDER 0x00000400 +#define DISPC_IRQSTATUS_VID1ENDWIND 0x00000800 +#define DISPC_IRQSTATUS_VID2FIFOUNDER 0x00001000 +#define DISPC_IRQSTATUS_VID2ENDWIND 0x00002000 +#define DISPC_IRQSTATUS_SYNCLOST 0x00004000 +#define DISPC_IRQENABLE 0x001C +#define DISPC_IRQENABLE_FRAMEDONE 0x00000001 +#define DISPC_IRQENABLE_VSYNC 0x00000002 +#define DISPC_IRQENABLE_EVSYNCEVEN 0x00000004 +#define DISPC_IRQENABLE_EVSYNCODD 0x00000008 +#define DISPC_IRQENABLE_ACBIASCOUNT 0x00000010 +#define DISPC_IRQENABLE_PROGLINENUM 0x00000020 +#define DISPC_IRQENABLE_GFXFIFOUNDER 0x00000040 +#define DISPC_IRQENABLE_GFXENDWINDOW 0x00000080 +#define DISPC_IRQENABLE_PALGAMMA 0x00000100 +#define DISPC_IRQENABLE_OCPERROR 0x00000200 +#define DISPC_IRQENABLE_VID1FIFOUNDER 0x00000400 +#define DISPC_IRQENABLE_VID1ENDWIND 0x00000800 +#define DISPC_IRQENABLE_VID2FIFOUNDER 0x00001000 +#define DISPC_IRQENABLE_VID2ENDWIND 0x00002000 +#define DISPC_IRQENABLE_SYNCLOST 0x00004000 +#define DISPC_CONTROL 0x0040 +#define DISPC_CONTROL_LCDENABLE 0x00000001 +#define DISPC_CONTROL_DIGITALENABLE 0x00000002 +#define DISPC_CONTROL_MONOCOLOR 0x00000004 +#define DISPC_CONTROL_STNTFT 0x00000008 +#define DISPC_CONTROL_M8B 0x00000010 +#define DISPC_CONTROL_GOLCD 0x00000020 +#define DISPC_CONTROL_GODIGITAL 0x00000040 +#define DISPC_CONTROL_TFTDITHEREN 0x00000080 +#define DISPC_CONTROL_TFTDATALINES_12 0x00000000 +#define DISPC_CONTROL_TFTDATALINES_16 0x00000100 +#define DISPC_CONTROL_TFTDATALINES_18 0x00000200 +#define DISPC_CONTROL_TFTDATALINES_24 0x00000300 +#define DISPC_CONTROL_SECURE 0x00000400 +#define DISPC_CONTROL_RFBIMODE 0x00000800 +#define DISPC_CONTROL_OVERLAYOPT 0x00001000 +#define DISPC_CONTROL_GPIN0 0x00002000 +#define DISPC_CONTROL_GPIN1 0x00004000 +#define DISPC_CONTROL_GPOUT0 0x00008000 +#define DISPC_CONTROL_GPOUT1 0x00010000 +#define DISPC_CONTROL_HT 0x00070000 +#define DISPC_CONTROL_HT_s(x) ((x) << 17) +#define DISPC_CONTROL_TDMENABLE 0x00100000 +#define DISPC_CONTROL_TDMPARALLEL_8 0x00000000 +#define DISPC_CONTROL_TDMPARALLEL_9 0x00200000 +#define DISPC_CONTROL_TDMPARALLEL_12 0x00400000 +#define DISPC_CONTROL_TDMPARALLEL_16 0x00600000 +#define DISPC_CONTROL_TDMCYCLE_1 0x00000000 +#define DISPC_CONTROL_TDMCYCLE_2 0x00800000 +#define DISPC_CONTROL_TDMCYCLE_3 0x00000000 +#define DISPC_CONTROL_TDMCYCLE_3_2 0x01800000 +#define DISPC_CONTROL_TDMUNUSED_0 0x00000000 +#define DISPC_CONTROL_TDMUNUSED_1 0x02000000 +#define DISPC_CONTROL_TDMUNUSED_M 0x04000000 +#define DISPC_CONFIG 0x0044 +#define DISPC_CONFIG_PIXELGATED 0x00000001 +#define DISPC_CONFIG_LOADMODE_PGE 0x00000000 +#define DISPC_CONFIG_LOADMODE_PG 0x00000002 +#define DISPC_CONFIG_LOADMODE_DATA 0x00000004 +#define DISPC_CONFIG_LOADMODE_DATA_PG 0x00000006 +#define DISPC_CONFIG_PALETTEGAMMA 0x00000008 +#define DISPC_CONFIG_PIXELDATAGATED 0x00000010 +#define DISPC_CONFIG_PIXELCLOCKGATED 0x00000020 +#define DISPC_CONFIG_HSYNCGATED 0x00000040 +#define DISPC_CONFIG_VSYNCGATED 0x00000080 +#define DISPC_CONFIG_ACBIAGATED 0x00000100 +#define DISPC_CONFIG_FUNCGATED 0x00000200 +#define DISPC_CONFIG_TCKLCDEN 0x00000400 +#define DISPC_CONFIG_TCKLCDSEL 0x00000800 +#define DISPC_CONFIG_TCKDIGEN 0x00001000 +#define DISPC_CONFIG_TCKDIGSEL 0x00002000 +#define DISPC_CAPABLE 0x0048 +#define DISPC_DEFAULT_COLOR0 0x004C +#define DISPC_DEFAULT_COLOR1 0x0050 +#define DISPC_TRANS_COLOR0 0x0054 +#define DISPC_TRANS_COLOR1 0x0058 +#define DISPC_LINE_STATUS 0x005C +#define DISPC_LINE_NUMBER 0x0060 +#define DISPC_TIMING_H 0x0064 +#define DISPC_TIMING_H_HSW_s(x) ((x) << 0) +#define DISPC_TIMING_H_HFP_s(x) ((x) << 8) +#define DISPC_TIMING_H_HBP_s(x) ((x) << 20) +#define DISPC_TIMING_V 0x0068 +#define DISPC_TIMING_V_VSW_s(x) ((x) << 0) +#define DISPC_TIMING_V_VFP_s(x) ((x) << 8) +#define DISPC_TIMING_V_VBP_s(x) ((x) << 20) +#define DISPC_POL_FREQ 0x006C +#define DISPC_POL_FREQ_ACB_s(x) ((x) << 0) +#define DISPC_POL_FREQ_ACBI_s(x) ((x) << 8) +#define DISPC_POL_FREQ_IVS 0x00001000 +#define DISPC_POL_FREQ_IHS 0x00002000 +#define DISPC_POL_FREQ_IPC 0x00004000 +#define DISPC_POL_FREQ_IEO 0x00008000 +#define DISPC_POL_FREQ_RF 0x00010000 +#define DISPC_POL_FREQ_ONOFF 0x00020000 +#define DISPC_DIVISOR 0x0070 +#define DISPC_DIVISOR_PCD_s(x) ((x) << 0) +#define DISPC_DIVISOR_LCD_s(x) ((x) << 16) +#define DISPC_SIZE_DIG 0x0078 +#define DISPC_SIZE_DIG_PPL_s(x) ((x) << 0) +#define DISPC_SIZE_DIG_LPP_s(x) ((x) << 16) +#define DISPC_SIZE_LCD 0x007C +#define DISPC_SIZE_LCD_PPL_s(x) ((x) << 0) +#define DISPC_SIZE_LCD_LPP_s(x) ((x) << 16) +#define DISPC_GFX_BA0 0x0080 +#define DISPC_GFX_BA1 0x0084 +#define DISPC_GFX_POSITION 0x0088 +#define DISPC_GFX_SIZE 0x008C +#define DISPC_GFX_SIZE_X_s(x) ((x) << 0) +#define DISPC_GFX_SIZE_Y_s(x) ((x) << 16) +#define DISPC_GFX_ATTRIBUTES 0x00A0 +#define DISPC_GFX_ATTRIBUTES_GFXENABLE 0x001 +#define DISPC_GFX_ATTRIBUTES_GFXFMT_1 0x000 +#define DISPC_GFX_ATTRIBUTES_GFXFMT_2 0x002 +#define DISPC_GFX_ATTRIBUTES_GFXFMT_4 0x004 +#define DISPC_GFX_ATTRIBUTES_GFXFMT_8 0x006 +#define DISPC_GFX_ATTRIBUTES_GFXFMT_12 0x008 +#define DISPC_GFX_ATTRIBUTES_GFXFMT_16 0x00c +#define DISPC_GFX_ATTRIBUTES_GFXFMT_24 0x010 +#define DISPC_GFX_ATTRIBUTES_GFXREPLICATE 0x020 +#define DISPC_GFX_ATTRIBUTES_BURST_4 0x000 +#define DISPC_GFX_ATTRIBUTES_BURST_8 0x040 +#define DISPC_GFX_ATTRIBUTES_BURST_16 0x080 +#define DISPC_GFX_ATTRIBUTES_GFXCHANNELOUT 0x100 +#define DISPC_GFX_ATTRIBUTES_NIBBLEMODE 0x200 +#define DISPC_GFX_ATTRIBUTES_ENDIAN 0x400 +#define DISPC_GFX_FIFO_THRESHOLD 0x00A4 +#define DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT 16 +#define DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT 0 +#define DISPC_GFX_FIFO_SIZE_STATUS 0x00A8 +#define DISPC_GFX_ROW_INC 0x00AC +#define DISPC_GFX_PIXEL_INC 0x00B0 +#define DISPC_GFX_WINDOW_SKIP 0x00B4 +#define DISPC_GFX_TABLE_BA 0x00B8 +#define DISPC_VID1_BA0 0x00BC +#define DISPC_VID1_BA1 0x00C0 +#define DISPC_VID1_POSITION 0x00C4 +#define DISPC_VID1_SIZE 0x00C8 +#define DISPC_VID1_ATTRIBUTES 0x00CC +#define DISPC_VID1_FIFO_THRESHOLD 0x00D0 +#define DISPC_VID1_FIFO_SIZE_STATUS 0x00D4 +#define DISPC_VID1_ROW_INC 0x00D8 +#define DISPC_VID1_PIXEL_INC 0x00DC +#define DISPC_VID1_FIR 0x00E0 +#define DISPC_VID1_PICTURE_SIZE 0x00E4 +#define DISPC_VID1_ACCU0 0x00E8 +#define DISPC_VID1_ACCU1 0x00EC +#define DISPC_VID1_FIR_COEF_H0 0x00F0 +#define DISPC_VID1_FIR_COEF_H1 0x00F8 +#define DISPC_VID1_FIR_COEF_H2 0x0100 +#define DISPC_VID1_FIR_COEF_H3 0x0108 +#define DISPC_VID1_FIR_COEF_H4 0x0110 +#define DISPC_VID1_FIR_COEF_H5 0x0118 +#define DISPC_VID1_FIR_COEF_H6 0x0120 +#define DISPC_VID1_FIR_COEF_H7 0x0128 +#define DISPC_VID1_FIR_COEF_HV0 0x00F4 +#define DISPC_VID1_FIR_COEF_HV1 0x00FC +#define DISPC_VID1_FIR_COEF_HV2 0x0104 +#define DISPC_VID1_FIR_COEF_HV3 0x010C +#define DISPC_VID1_FIR_COEF_HV4 0x0114 +#define DISPC_VID1_FIR_COEF_HV5 0x011C +#define DISPC_VID1_FIR_COEF_HV6 0x0124 +#define DISPC_VID1_FIR_COEF_HV7 0x012C +#define DISPC_VID1_CONV_COEF0 0x0130 +#define DISPC_VID1_CONV_COEF1 0x0134 +#define DISPC_VID1_CONV_COEF2 0x0138 +#define DISPC_VID1_CONV_COEF3 0x013C +#define DISPC_VID1_CONV_COEF4 0x0140 +#define DISPC_VID2_BA0 0x014C +#define DISPC_VID2_BA1 0x0150 +#define DISPC_VID2_POSITION 0x0154 +#define DISPC_VID2_SIZE 0x0158 +#define DISPC_VID2_ATTRIBUTES 0x015C +#define DISPC_VID2_FIFO_THRESHOLD 0x0160 +#define DISPC_VID2_FIFO_SIZE_STATUS 0x0164 +#define DISPC_VID2_ROW_INC 0x0168 +#define DISPC_VID2_PIXEL_INC 0x016C +#define DISPC_VID2_FIR 0x0170 +#define DISPC_VID2_PICTURE_SIZE 0x0174 +#define DISPC_VID2_ACCU0 0x0178 +#define DISPC_VID2_ACCU1 0x017C +#define DISPC_VID2_FIR_COEF_H0 0x0180 +#define DISPC_VID2_FIR_COEF_H1 0x0188 +#define DISPC_VID2_FIR_COEF_H2 0x0190 +#define DISPC_VID2_FIR_COEF_H3 0x0198 +#define DISPC_VID2_FIR_COEF_H4 0x01A0 +#define DISPC_VID2_FIR_COEF_H5 0x01A8 +#define DISPC_VID2_FIR_COEF_H6 0x01B0 +#define DISPC_VID2_FIR_COEF_H7 0x01B8 +#define DISPC_VID2_FIR_COEF_HV0 0x0184 +#define DISPC_VID2_FIR_COEF_HV1 0x018C +#define DISPC_VID2_FIR_COEF_HV2 0x0194 +#define DISPC_VID2_FIR_COEF_HV3 0x019C +#define DISPC_VID2_FIR_COEF_HV4 0x01A4 +#define DISPC_VID2_FIR_COEF_HV5 0x01AC +#define DISPC_VID2_FIR_COEF_HV6 0x01B4 +#define DISPC_VID2_FIR_COEF_HV7 0x01BC +#define DISPC_VID2_CONV_COEF0 0x01C0 +#define DISPC_VID2_CONV_COEF1 0x01C4 +#define DISPC_VID2_CONV_COEF2 0x01C8 +#define DISPC_VID2_CONV_COEF3 0x01CC +#define DISPC_VID2_CONV_COEF4 0x01D0 +#define DISPC_DATA_CYCLE1 0x01D4 +#define DISPC_DATA_CYCLE2 0x01D8 +#define DISPC_DATA_CYCLE3 0x01DC +#define DISPC_SIZE 0x0200 + +/* RFBI */ +#define RFBI_REVISION 0x0000 +#define RFBI_SYSCONFIG 0x0010 +#define RFBI_SYSSTATUS 0x0014 +#define RFBI_CONTROL 0x0040 +#define RFBI_PIXEL_CNT 0x0044 +#define RFBI_LINE_NUMBER 0x0048 +#define RFBI_CMD 0x004C +#define RFBI_PARAM 0x0050 +#define RFBI_DATA 0x0054 +#define RFBI_READ 0x0058 +#define RFBI_STATUS 0x005C +#define RFBI_CONFIG0 0x0060 +#define RFBI_CONFIG1 0x0078 +#define RFBI_ONOFF_TIME0 0x0064 +#define RFBI_ONOFF_TIME1 0x007C +#define RFBI_CYCLE_TIME0 0x0068 +#define RFBI_CYCLE_TIME1 0x0080 +#define RFBI_DATA_CYCLE1_0 0x006C +#define RFBI_DATA_CYCLE1_1 0x0084 +#define RFBI_DATA_CYCLE2_0 0x0070 +#define RFBI_DATA_CYCLE2_1 0x0088 +#define RFBI_DATA_CYCLE3_0 0x0074 +#define RFBI_DATA_CYCLE3_1 0x008C +#define RFBI_VSYNC_WIDTH 0x0090 +#define RFBI_HSYNC_WIDTH 0x0094 + +/* VENC1 */ +#define REV_ID 0x0000 +#define STATUS 0x0004 +#define F_CONTROL 0x0008 +#define VIDOUT_CTRL 0x0010 +#define SYNC_CTRL 0x0014 +#define LLEN 0x001C +#define FLENS 0x0020 +#define HFLTR_CTRL 0x0024 +#define CC_CARR_WSS_CARR 0x0028 +#define C_PHASE 0x002C +#define GAIN_U 0x0030 +#define GAIN_V 0x0034 +#define GAIN_Y 0x0038 +#define BLACK_LEVEL 0x003C +#define BLANK_LEVEL 0x0040 +#define X_COLOR 0x0044 +#define M_CONTROL 0x0048 +#define BSTAMP_WSS_DATA 0x004C +#define S_CARR 0x0050 +#define LINE21 0x0054 +#define LN_SEL 0x0058 +#define L21_WC_CTL 0x005C +#define HTRIGGER_VTRIGGER 0x0060 +#define SAVID_EAVID 0x0064 +#define FLEN_FAL 0x0068 +#define LAL_PHASE_RESET 0x006C +#define HS_INT_START_STOP_X 0x0070 +#define HS_EXT_START_STOP_X 0x0074 +#define VS_INT_START_X 0x0078 +#define VS_INT_STOP_X_VS_INT_START_Y 0x007C +#define VS_INT_STOP_Y_VS_EXT_START_X 0x0080 +#define VS_EXT_STOP_X_VS_EXT_START_Y 0x0084 +#define VS_EXT_STOP_Y 0x0088 +#define AVID_START_STOP_X 0x0090 +#define AVID_START_STOP_Y 0x0094 +#define FID_INT_START_X_FID_INT_START_Y 0x00A0 +#define FID_INT_OFFSET_Y_FID_EXT_START_X 0x00A4 +#define FID_EXT_START_Y_FID_EXT_OFFSET_Y 0x00A8 +#define TVDETGP_INT_START_STOP_X 0x00B0 +#define TVDETGP_INT_START_STOP_Y 0x00B4 +#define GEN_CTRL 0x00B8 +#define DAC_TST_DAC_A 0x00C4 +#define DAC_B_DAC_C 0x00C8 + + +/* NO CONSOLE SUPPORT */ + + +/* assumes 565 panel. */ +struct omdisplay_panel_data { + int width; + int height; + int horiz_sync_width; + int horiz_front_porch; + int horiz_back_porch; + int vert_sync_width; + int vert_front_porch; + int vert_back_porch; + int panel_flags; + int sync; + int depth; +#define PANEL_SYNC_H_ACTIVE_HIGH 1 +#define PANEL_SYNC_V_ACTIVE_HIGH 2 + int linebytes; +}; + +#define PIXELDEPTH 16 +#define PIXELWIDTH 2 + +struct omdisplay_panel_data default_panel = { + 240, /* Width */ + 322, /* Height */ + 9, 9, 19, /* horiz sync, fp, bp */ + 1, 2, 2, /* vert sync, fp, bp */ + 0, /* flags */ + 0, /* sync */ + PIXELDEPTH, + 240*PIXELWIDTH +}; + +struct omdisplay_screen { + LIST_ENTRY(omdisplay_screen) link; + + /* Frame buffer */ + bus_dmamap_t dma; + bus_dma_segment_t segs[1]; + int nsegs; + size_t buf_size; + size_t map_size; + void *buf_va; + int depth; + + /* rasterop */ + struct rasops_info rinfo; +}; + +struct omdisplay_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_dsioh; + bus_space_handle_t sc_dcioh; + bus_space_handle_t sc_rfbioh; + bus_space_handle_t sc_venioh; + bus_dma_tag_t sc_dma_tag; + + void *sc_ih; + + int sc_nscreens; + LIST_HEAD(,omdisplay_screen) sc_screens; + + struct omdisplay_panel_data *sc_geometry; + struct omdisplay_screen *sc_active; +}; + +int omdisplay_match(struct device *parent, void *v, void *aux); +void omdisplay_attach(struct device *parent, struct device *self, void *args); +int omdisplay_activate(struct device *, int); +int omdisplay_ioctl(void *v, u_long cmd, caddr_t data, int flag, + struct proc *p); +void omdisplay_burner(void *v, u_int on, u_int flags); +int omdisplay_show_screen(void *v, void *cookie, int waitok, + void (*cb)(void *, int, int), void *cbarg); +int omdisplay_param(struct omdisplay_softc *sc, ulong cmd, + struct wsdisplay_param *dp); +int omdisplay_max_brightness(void); +int omdisplay_get_brightness(void); +void omdisplay_set_brightness(int newval); +void omdisplay_set_brightness_internal(int newval); +int omdisplay_get_backlight(void); +void omdisplay_set_backlight(int on); +void omdisplay_blank(int blank); +void omdisplay_suspend(struct omdisplay_softc *sc); +void omdisplay_resume(struct omdisplay_softc *sc); +void omdisplay_initialize(struct omdisplay_softc *sc, + struct omdisplay_panel_data *geom); +void omdisplay_setup_rasops(struct omdisplay_softc *sc, + struct rasops_info *rinfo); +int omdisplay_alloc_screen(void *v, const struct wsscreen_descr *_type, + void **cookiep, int *curxp, int *curyp, long *attrp); +int omdisplay_new_screen(struct omdisplay_softc *sc, + struct omdisplay_screen *scr, int depth); +paddr_t omdisplay_mmap(void *v, off_t offset, int prot); +void omdisplay_free_screen(void *v, void *cookie); +void omdisplay_start(struct omdisplay_softc *sc); +void omdisplay_stop(struct omdisplay_softc *sc); +int omdisplay_intr(void *v); +void omdisplay_dumpreg(struct omdisplay_softc *sc); + +struct cfattach omdisplay_ca = { + sizeof (struct omdisplay_softc), omdisplay_match, omdisplay_attach, + NULL, omdisplay_activate +}; + +struct cfdriver omdisplay_cd = { + NULL, "omdisplay", DV_DULL +}; + +struct wsdisplay_accessops omdisplay_accessops = { + omdisplay_ioctl, + omdisplay_mmap, + omdisplay_alloc_screen, + omdisplay_free_screen, + omdisplay_show_screen, + NULL, /* load font */ + NULL, /* scrollback */ + NULL, /* getchar */ + omdisplay_burner + +}; + +struct omdisplay_wsscreen_descr { + struct wsscreen_descr c; /* standard descriptor */ + int depth; /* bits per pixel */ + int flags; /* rasops flags */ +}; + +struct omdisplay_wsscreen_descr omdisplay_screen = { + { + "std" + }, + 16, /* bits per pixel */ + 0 /* rotate */ +}; + +const struct wsscreen_descr *omdisplay_scr_descr[] = { + &omdisplay_screen.c +}; + +/* XXX - what about flip phones with CLI */ +const struct wsscreen_list omdisplay_screen_list = { + sizeof omdisplay_scr_descr / sizeof omdisplay_scr_descr[0], + omdisplay_scr_descr +}; + + +int +omdisplay_match(struct device *parent, void *v, void *aux) +{ + /* XXX */ + return (1); +} + +void +omdisplay_attach(struct device *parent, struct device *self, void *args) +{ + struct ahb_attach_args *aa = args; + struct omdisplay_softc *sc = (struct omdisplay_softc *) self; + struct wsemuldisplaydev_attach_args wsaa; + + + sc->sc_iot = aa->aa_iot; + + if (bus_space_map(sc->sc_iot, aa->aa_addr, OMDISPLAY_SIZE, 0, + &sc->sc_dsioh)) + panic("omdisplay_attach: bus_space_map failed!"); + + if (bus_space_subregion(sc->sc_iot, sc->sc_dsioh, 0x400, 1024, + &sc->sc_dcioh)) + panic("omdisplay_attach: bus_space_submap failed!"); + + if (bus_space_subregion(sc->sc_iot, sc->sc_dsioh, 0x800, 1024, + &sc->sc_rfbioh)) + panic("omdisplay_attach: bus_space_submap failed!"); + + if (bus_space_subregion(sc->sc_iot, sc->sc_dsioh, 0xc00, 1024, + &sc->sc_venioh)) + panic("omdisplay_attach: bus_space_submap failed!"); + + + sc->sc_nscreens = 0; + LIST_INIT(&sc->sc_screens); + + sc->sc_dma_tag = aa->aa_dmat; + + sc->sc_ih = arm_intr_establish(aa->aa_intr, IPL_BIO /* XXX */, + omdisplay_intr, sc, sc->sc_dev.dv_xname); + + printf ("\n"); + + sc->sc_geometry = &default_panel; + + { + /* XXX - dummy? */ + struct rasops_info dummy; + + omdisplay_initialize(sc, sc->sc_geometry); + + /* + * Initialize a dummy rasops_info to compute fontsize and + * the screen size in chars. + */ + bzero(&dummy, sizeof(dummy)); + omdisplay_setup_rasops(sc, &dummy); + } + + wsaa.console = 0; + wsaa.scrdata = &omdisplay_screen_list; + wsaa.accessops = &omdisplay_accessops; + wsaa.accesscookie = sc; + wsaa.defaultscreens = 0; + + (void)config_found(self, &wsaa, wsemuldisplaydevprint); + + /* backlight? */ +} + + +int +omdisplay_ioctl(void *v, u_long cmd, caddr_t data, int flag, struct proc *p) +{ + struct omdisplay_softc *sc = v; + struct wsdisplay_fbinfo *wsdisp_info; + struct omdisplay_screen *scr = sc->sc_active; + int res = EINVAL; + + switch (cmd) { + case WSDISPLAYIO_GETPARAM: + case WSDISPLAYIO_SETPARAM: + res = omdisplay_param(sc, cmd, (struct wsdisplay_param *)data); + break; + case WSDISPLAYIO_GTYPE: + *(u_int *)data = WSDISPLAY_TYPE_PXALCD; /* XXX */ + break; + + case WSDISPLAYIO_GINFO: + wsdisp_info = (struct wsdisplay_fbinfo *)data; + + wsdisp_info->height = sc->sc_geometry->height; + wsdisp_info->width = sc->sc_geometry->width; + wsdisp_info->depth = 16; /* XXX */ + wsdisp_info->cmsize = 0; + break; + + case WSDISPLAYIO_GETCMAP: + case WSDISPLAYIO_PUTCMAP: + return EINVAL; /* XXX Colormap */ + + case WSDISPLAYIO_SVIDEO: + case WSDISPLAYIO_GVIDEO: + break; + + case WSDISPLAYIO_GCURPOS: + case WSDISPLAYIO_SCURPOS: + case WSDISPLAYIO_GCURMAX: + case WSDISPLAYIO_GCURSOR: + case WSDISPLAYIO_SCURSOR: + default: + return -1; /* not implemented */ + + case WSDISPLAYIO_LINEBYTES: + if (scr != NULL) + *(u_int *)data = scr->rinfo.ri_stride; + else + *(u_int *)data = 0; + break; + + } + + if (res == EINVAL) + res = omdisplay_ioctl(v, cmd, data, flag, p); + + return res; +} + +void +omdisplay_burner(void *v, u_int on, u_int flags) +{ + + omdisplay_set_brightness(on ? omdisplay_get_brightness() : 0); + + /* GPIO controls for appsliver */ + if (on) { + omgpio_set_bit(93); /* 1 enable backlight */ + omgpio_set_dir(93, OMGPIO_DIR_OUT); + omgpio_clear_bit(26); /* 0 enable LCD */ + omgpio_set_dir(26, OMGPIO_DIR_OUT); + } else { + omgpio_clear_bit(93); /* 0 disable backlt */ + omgpio_set_dir(93, OMGPIO_DIR_OUT); + omgpio_set_bit(26); /* 1 disable LCD */ + omgpio_set_dir(26, OMGPIO_DIR_OUT); + } +} + +int +omdisplay_show_screen(void *v, void *cookie, int waitok, + void (*cb)(void *, int, int), void *cbarg) +{ + struct omdisplay_softc *sc = v; + struct rasops_info *ri = cookie; + struct omdisplay_screen *scr = ri->ri_hw, *old; + + old = sc->sc_active; + if (old == scr) + return 0; + + if (old != NULL) + ; /* Stop old screen */ + + sc->sc_active = scr; + omdisplay_initialize(sc, sc->sc_geometry); + + /* Turn on LCD */ + omdisplay_burner(v, 1, 0); + + return (0); +} + + + +/* + * wsdisplay I/O controls + */ +int +omdisplay_param(struct omdisplay_softc *sc, ulong cmd, + struct wsdisplay_param *dp) +{ + int res = EINVAL; + + switch (dp->param) { + case WSDISPLAYIO_PARAM_BACKLIGHT: + if (cmd == WSDISPLAYIO_GETPARAM) { + dp->min = 0; + dp->max = 1; + dp->curval = omdisplay_get_backlight(); + res = 0; + } else if (cmd == WSDISPLAYIO_SETPARAM) { +/* XXX */ +// omdisplay_set_backlight(dp->curval); + res = 0; + } + break; + + case WSDISPLAYIO_PARAM_CONTRAST: + /* unsupported */ + res = ENOTTY; + break; + + case WSDISPLAYIO_PARAM_BRIGHTNESS: + if (cmd == WSDISPLAYIO_GETPARAM) { + dp->min = 1; + dp->max = omdisplay_max_brightness(); + dp->curval = omdisplay_get_brightness(); + res = 0; + } else if (cmd == WSDISPLAYIO_SETPARAM) { +/* XXX */ +// omdisplay_set_brightness(dp->curval); + res = 0; + } + break; + } + + return res; +} + + +/* + * LCD backlight + */ + +static int lcdbrightnesscurval = 1; +static int lcdislit = 1; +static int lcdisblank = 0; + +struct lcd_backlight { + int duty; /* LZ9JG18 DAC value */ + int cont; /* BACKLIGHT_CONT signal */ + int on; /* BACKLIGHT_ON signal */ +}; + +const struct lcd_backlight lcd_bl[] = { + { 0x00, 0, 0 }, /* 0: Off */ + { 0x00, 0, 1 }, /* 1: 0% */ + { 0x01, 0, 1 }, /* 2: 20% */ + { 0x07, 0, 1 }, /* 3: 40% */ + { 0x01, 1, 1 }, /* 4: 60% */ + { 0x07, 1, 1 }, /* 5: 80% */ + { 0x11, 1, 1 }, /* 6: 100% */ + { -1, -1, -1 } /* 7: Invalid */ +}; +#define CURRENT_BACKLIGHT lcd_bl + +int +omdisplay_max_brightness(void) +{ + int i; + + for (i = 0; CURRENT_BACKLIGHT[i].duty != -1; i++) + ; + return i - 1; +} + +int +omdisplay_get_brightness(void) +{ + + return lcdbrightnesscurval; +} + +void +omdisplay_set_brightness(int newval) +{ + int max; + + max = omdisplay_max_brightness(); + if (newval < 0) + newval = 0; + else if (newval > max) + newval = max; + + if (omdisplay_get_backlight() && !lcdisblank) + omdisplay_set_brightness_internal(newval); + + if (newval > 0) + lcdbrightnesscurval = newval; +} + +void +omdisplay_set_brightness_internal(int newval) +{ + static int curval = 1; + int i; + + /* + * It appears that the C3000 backlight can draw too much power if we + * switch it from a low to a high brightness. Increasing brightness + * in steps avoids this issue. + */ + if (newval > curval) { + for (i = curval + 1; i <= newval; i++) { +/* atlas controls */ + /* CURRENT_BACKLIGHT[newval].duty); */ + } + } else { +/* atlas controls */ + /* CURRENT_BACKLIGHT[newval].duty); */ + } + + curval = newval; +} + +int +omdisplay_get_backlight(void) +{ + + return lcdislit; +} + +void +omdisplay_set_backlight(int on) +{ + + if (!on) { + omdisplay_set_brightness(0); + lcdislit = 0; + } else { + lcdislit = 1; + omdisplay_set_brightness(omdisplay_get_brightness()); + } +} + +void +omdisplay_blank(int blank) +{ + + if (blank) { + omdisplay_set_brightness(0); + lcdisblank = 1; + } else { + lcdisblank = 0; + omdisplay_set_brightness(omdisplay_get_brightness()); + } +} + +void +omdisplay_suspend(struct omdisplay_softc *sc) +{ + if (sc->sc_active != NULL) { + omdisplay_stop(sc); + /* XXX disable clocks */ + } +} + +void +omdisplay_resume(struct omdisplay_softc *sc) +{ + if (sc->sc_active != NULL) { + /* XXX - clocks? */ + omdisplay_initialize(sc, sc->sc_geometry); + omdisplay_start(sc); + } +} + +void +omdisplay_activate(struct device *self, int act) +{ + struct omdisplay_softc *sc = (struct omdisplay_softc *)self; + + switch (act) { + case DVACT_SUSPEND: + omdisplay_set_brightness(0); + omdisplay_suspend(sc); + break; + case DVACT_RESUME: + omdisplay_resume(sc); + omdisplay_set_brightness(omdisplay_get_brightness()); + break; + } + return 0; +} + +void +omdisplay_initialize(struct omdisplay_softc *sc, + struct omdisplay_panel_data *geom) +{ + struct omdisplay_screen *scr; + u_int32_t reg; + u_int32_t mode; +#if 0 + int den, nom; /* pixel rate */ +#endif + + + reg = bus_space_read_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL); + + scr = sc->sc_active; + + if (reg & (DISPC_CONTROL_LCDENABLE|DISPC_CONTROL_DIGITALENABLE)) { + omdisplay_stop(sc); + } + + /* XXX - enable clocks */ + + /* disable all interrupts */ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_IRQENABLE, 0); + + /* GPIOs ? */ + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONFIG, + DISPC_CONFIG_LOADMODE_PG|DISPC_CONFIG_LOADMODE_DATA); + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DEFAULT_COLOR0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DEFAULT_COLOR1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TRANS_COLOR0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TRANS_COLOR1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_LINE_NUMBER, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DATA_CYCLE1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DATA_CYCLE2, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DATA_CYCLE3, 0); + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_SYSCONFIG, + DISPC_SYSCONFIG_SIDLEMODE_NONE| + DISPC_SYSCONFIG_MIDLEMODE_NONE); + +#if 0 + if (geom->panel_flags & LCDPANEL_TDM) { + nom = tdmflags >>8 & 0x3; + den = tdmflags & 0x3; + } else { + nom = 1; + den = 1; + } + hsync = geom->width*den/nom + geom->horiz_sync_width + + geom->horiz_front_porch + geom->horiz_back_porch; +#endif + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TIMING_H, + DISPC_TIMING_H_HSW_s(geom->horiz_sync_width) | + DISPC_TIMING_H_HFP_s(geom->horiz_front_porch) | + DISPC_TIMING_H_HBP_s(geom->horiz_back_porch)); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_TIMING_V, + DISPC_TIMING_V_VSW_s(geom->vert_sync_width) | + DISPC_TIMING_V_VFP_s(geom->vert_front_porch) | + DISPC_TIMING_V_VBP_s(geom->vert_back_porch)); + + reg = 0; + if (geom->sync & PANEL_SYNC_H_ACTIVE_HIGH) + reg |= DISPC_POL_FREQ_IHS; + if (geom->sync & PANEL_SYNC_V_ACTIVE_HIGH) + reg |= DISPC_POL_FREQ_IVS; + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_POL_FREQ, reg); + + + /* clkdiv = pixclock/period; */ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_SIZE_LCD, + DISPC_SIZE_LCD_PPL_s(geom->width-1) | + DISPC_SIZE_LCD_LPP_s(geom->height-1)); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_SIZE_DIG, + DISPC_SIZE_LCD_PPL_s(geom->width-1) | + DISPC_SIZE_LCD_LPP_s(geom->height-1)); + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_SIZE, + DISPC_GFX_SIZE_X_s(geom->width-1) | + DISPC_GFX_SIZE_Y_s(geom->height-1)); + + + /* XXX!!! */ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_DIVISOR, + DISPC_DIVISOR_LCD_s(1) | DISPC_DIVISOR_PCD_s(6)); + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_BA0, + scr->segs[0].ds_addr); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_BA1, + scr->segs[0].ds_addr); + + /* non-rotated */ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_PIXEL_INC, 1); + + + /* XXX 24bit -> 32 pixels */ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_ROW_INC, + 1 + scr->rinfo.ri_stride - + (scr->rinfo.ri_width * scr->rinfo.ri_depth / 8)); + + switch (geom->depth) { + case 1: + mode = DISPC_GFX_ATTRIBUTES_GFXFMT_1; + break; + case 2: + mode = DISPC_GFX_ATTRIBUTES_GFXFMT_2; + break; + case 4: + mode = DISPC_GFX_ATTRIBUTES_GFXFMT_4; + break; + case 8: + mode = DISPC_GFX_ATTRIBUTES_GFXFMT_8; + break; + case 12: + mode = DISPC_GFX_ATTRIBUTES_GFXFMT_12; + break; + case 16: + mode = DISPC_GFX_ATTRIBUTES_GFXFMT_16; + break; + case 24: + mode = DISPC_GFX_ATTRIBUTES_GFXFMT_24; + break; + default: + panic("invalid depth %d", geom->depth); + } + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_ATTRIBUTES, + DISPC_GFX_ATTRIBUTES_GFXENABLE | mode | + DISPC_GFX_ATTRIBUTES_BURST_8); + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_POSITION, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_WINDOW_SKIP, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_FIFO_THRESHOLD, + (0xfc << DISPC_GFX_FIFO_THRESHOLD_HIGH_SHIFT) | + (0xc0 << DISPC_GFX_FIFO_THRESHOLD_LOW_SHIFT)); + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_ROW_INC, 1); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_PIXEL_INC, 1); + + /* DISPC_CONFIG_PALETTEGAMMA not enabled */ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_GFX_TABLE_BA, + scr->segs[0].ds_addr); + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_BA0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_BA1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_SIZE, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ATTRIBUTES, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIFO_THRESHOLD, + 0xc00040); /* XXX */ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIFO_SIZE_STATUS, + 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ROW_INC, 1); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_PIXEL_INC, 1); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_PICTURE_SIZE, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ACCU0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_ACCU1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H2, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H3, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H4, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H5, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H6, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_H7, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV2, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV3, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV4, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV5, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV6, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_FIR_COEF_HV7, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF2, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF3, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID1_CONV_COEF4, 0); + + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_BA0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_BA1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_SIZE, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ATTRIBUTES, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIFO_THRESHOLD, + 0xc00040); /* XXX */ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIFO_SIZE_STATUS, + 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ROW_INC, 1); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_PIXEL_INC, 1); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_PICTURE_SIZE, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ACCU0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_ACCU1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H2, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H3, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H4, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H5, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H6, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_H7, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV2, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV3, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV4, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV5, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV6, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_FIR_COEF_HV7, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF0, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF1, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF2, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF3, 0); + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_VID2_CONV_COEF4, 0); + + omdisplay_start(sc); +} + +void +omdisplay_setup_rasops(struct omdisplay_softc *sc, struct rasops_info *rinfo) +{ + struct omdisplay_wsscreen_descr *descr; + struct omdisplay_panel_data *geom; + + descr = &omdisplay_screen; + geom = sc->sc_geometry; + + rinfo->ri_flg = descr->flags; + rinfo->ri_depth = descr->depth; + rinfo->ri_width = geom->width; + rinfo->ri_height = geom->height; + rinfo->ri_stride = geom->linebytes; + + /* pixel position */ + if (descr->depth == 16) { + rinfo->ri_rnum = 5; + rinfo->ri_rpos = 11; + rinfo->ri_gnum = 6; + rinfo->ri_gpos = 5; + rinfo->ri_bnum = 5; + rinfo->ri_bpos = 0; + } + + if (descr->c.nrows == 0) { + /* get rasops to compute screen size the first time */ + rasops_init(rinfo, 100, 100); + } else { + if (descr->flags != 0) /* rotate */ + rasops_init(rinfo, descr->c.ncols, descr->c.nrows); + else + rasops_init(rinfo, descr->c.nrows, descr->c.ncols); + } + + descr->c.nrows = rinfo->ri_rows; + descr->c.ncols = rinfo->ri_cols; + descr->c.capabilities = rinfo->ri_caps; + descr->c.textops = &rinfo->ri_ops; + +} + + +int +omdisplay_alloc_screen(void *v, const struct wsscreen_descr *_type, + void **cookiep, int *curxp, int *curyp, long *attrp) +{ + struct omdisplay_softc *sc = v; + struct omdisplay_screen *scr; + struct rasops_info *ri; + struct omdisplay_wsscreen_descr *type = + (struct omdisplay_wsscreen_descr *)_type; + int error; + + scr = malloc(sizeof *scr, M_DEVBUF, (cold ? M_NOWAIT : M_WAITOK)); + if (scr == NULL) + return (ENOMEM); + + error = omdisplay_new_screen(sc, scr, type->depth); + if (error != 0) { + free(scr, M_DEVBUF); + return (error); + } + + /* + * initialize raster operation for this screen. + */ + ri = &scr->rinfo; + ri->ri_hw = (void *)scr; + ri->ri_bits = scr->buf_va; + omdisplay_setup_rasops(sc, ri); + + /* assumes 16 bpp */ + ri->ri_ops.alloc_attr(ri, 0, 0, 0, attrp); + + *cookiep = ri; + *curxp = 0; + *curyp = 0; + + return 0; +} + +/* + * Create and initialize a new screen buffer. + */ +int +omdisplay_new_screen(struct omdisplay_softc *sc, + struct omdisplay_screen *scr, int depth) +{ + bus_space_tag_t iot; + bus_space_handle_t ioh; + bus_dma_tag_t dma_tag; + struct omdisplay_panel_data *geometry; + int width, height; + bus_size_t size; + int error, palette_size; + int busdma_flag = (cold ? BUS_DMA_NOWAIT : BUS_DMA_WAITOK); + + if (sc != NULL) { + iot = sc->sc_iot; + ioh = sc->sc_dcioh; + dma_tag = sc->sc_dma_tag; + geometry = sc->sc_geometry; + } else { + /* We are creating the console screen. */ +#if 0 + iot = omdisplay_console.iot; + ioh = omdisplay_console.ioh; + dma_tag = omdisplay_console.dma_tag; + geometry = omdisplay_console.geometry; +#endif + } + + width = geometry->width; + height = geometry->height; + palette_size = 0; + + switch (depth) { + case 1: + case 2: + case 4: + case 8: + palette_size = (1 << depth) * sizeof (uint16_t); + /* FALLTHROUGH */ + case 16: + case 24: + size = geometry->height * geometry->linebytes; + break; + default: + printf("%s: Unknown depth (%d)\n", + sc != NULL ? sc->sc_dev.dv_xname : "console", depth); + return (EINVAL); + } + + bzero(scr, sizeof *scr); + + scr->nsegs = 0; + scr->depth = depth; + scr->buf_size = size; + scr->buf_va = NULL; + size = roundup(size, 16); +#if 0 + + 3 * sizeof (struct lcd_dma_descriptor) + + palette_size; +#endif + + error = bus_dmamem_alloc(dma_tag, size, 0x100000, 0, + scr->segs, 1, &(scr->nsegs), busdma_flag); + if (error != 0 || scr->nsegs != 1) { + /* XXX: Actually we can handle nsegs > 1 case by means + of multiple DMA descriptors for a panel. It would + make code here a bit hairy */ + if (error == 0) + error = E2BIG; + goto bad; + } + + error = bus_dmamem_map(dma_tag, scr->segs, scr->nsegs, + size, (caddr_t *)&(scr->buf_va), busdma_flag | BUS_DMA_COHERENT); + if (error != 0) + goto bad; + + memset(scr->buf_va, 0, scr->buf_size); + bcopy(splash, scr->buf_va, + sizeof (splash) > scr->buf_size ? scr->buf_size : sizeof (splash)); + + /* map memory for DMA */ + if (bus_dmamap_create(dma_tag, 1024 * 1024 * 2, 1, + 1024 * 1024 * 2, 0, busdma_flag, &scr->dma)) + goto bad; + error = bus_dmamap_load(dma_tag, scr->dma, + scr->buf_va, size, NULL, busdma_flag); + if (error != 0) { + goto bad; + } + + scr->map_size = size; /* used when unmap this. */ + + if (sc != NULL) { + LIST_INSERT_HEAD(&(sc->sc_screens), scr, link); + sc->sc_nscreens++; + } + + omdisplay_initialize(sc, geometry); + + return (0); + + bad: + if (scr->buf_va) + bus_dmamem_unmap(dma_tag, scr->buf_va, size); + if (scr->nsegs) + bus_dmamem_free(dma_tag, scr->segs, scr->nsegs); + return (error); +} +paddr_t +omdisplay_mmap(void *v, off_t offset, int prot) +{ + struct omdisplay_softc *sc = v; + struct omdisplay_screen *screen = sc->sc_active; /* ??? */ + + if ((offset & PAGE_MASK) != 0) + return (-1); + + if (screen == NULL) + return (-1); + + if (offset < 0 || + offset >= screen->rinfo.ri_stride * screen->rinfo.ri_height) + return (-1); + + return (bus_dmamem_mmap(sc->sc_dma_tag, screen->segs, screen->nsegs, + offset, prot, BUS_DMA_WAITOK | BUS_DMA_COHERENT)); +} + +void +omdisplay_free_screen(void *v, void *cookie) +{ + struct omdisplay_softc *sc = v; + struct rasops_info *ri = cookie; + struct omdisplay_screen *scr = ri->ri_hw; + + LIST_REMOVE(scr, link); + sc->sc_nscreens--; + if (scr == sc->sc_active) { + /* at first, we need to stop LCD DMA */ + sc->sc_active = NULL; + +#ifdef DEBUG + printf("lcd_free on active screen\n"); +#endif + + omdisplay_stop(sc); + } + + if (scr->buf_va) + bus_dmamem_unmap(sc->sc_dma_tag, scr->buf_va, scr->map_size); + + if (scr->nsegs > 0) + bus_dmamem_free(sc->sc_dma_tag, scr->segs, scr->nsegs); + + free(scr, M_DEVBUF); +} + +void +omdisplay_start(struct omdisplay_softc *sc) +{ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL, + DISPC_CONTROL_GPOUT0 | DISPC_CONTROL_GPOUT1 | + DISPC_CONTROL_TFTDATALINES_18 /*XXX 18? */ | + DISPC_CONTROL_STNTFT | + DISPC_CONTROL_GOLCD | + DISPC_CONTROL_LCDENABLE); +} + +void +omdisplay_stop(struct omdisplay_softc *sc) +{ + bus_space_write_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL, + bus_space_read_4(sc->sc_iot, sc->sc_dcioh, DISPC_CONTROL) & + ~(DISPC_CONTROL_DIGITALENABLE|DISPC_CONTROL_LCDENABLE)); + + /* XXX - wait for end of frame? */ +} + +int +omdisplay_intr(void *v) +{ + /* XXX */ + return 1; +} + diff --git a/sys/arch/armv7/omap/omdog.c b/sys/arch/armv7/omap/omdog.c new file mode 100644 index 00000000000..73bbc73391a --- /dev/null +++ b/sys/arch/armv7/omap/omdog.c @@ -0,0 +1,113 @@ +/* $OpenBSD: omdog.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ +/* + * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/queue.h> +#include <sys/malloc.h> +#include <sys/device.h> +#include <sys/evcount.h> +#include <sys/socket.h> +#include <sys/timeout.h> +#include <machine/intr.h> +#include <machine/bus.h> +#include <armv7/omap/omapvar.h> +#include <armv7/omap/omgpiovar.h> + +/* registers */ +#define WIDR 0x00 +#define WD_SYSCONFIG 0x10 +#define WD_SYSSTATUS 0x14 +#define WISR 0x18 +#define WIER 0x1C +#define WCLR 0x24 +#define WCRR 0x28 +#define WLDR 0x2C +#define WTGR 0x30 +#define WWPS 0x34 +#define WWPS_PEND_ALL 0x1f +#define WSPR 0x48 + + +struct omdog_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +struct omdog_softc *omdog_sc; + +/* + * to enable the watchdog, write 0xXXXXbbbb then 0xXXXX4444 to WSPR + * to disable the watchdog, write 0xXXXXaaaa then 0xXXXX5555 to WSPR + */ + +void omdog_attach(struct device *parent, struct device *self, void *args); +void omdog_wpending(int flags); + +struct cfattach omdog_ca = { + sizeof (struct omdog_softc), NULL, omdog_attach +}; + +struct cfdriver omdog_cd = { + NULL, "omdog", DV_DULL +}; + +void +omdog_attach(struct device *parent, struct device *self, void *args) +{ + struct omap_attach_args *oa = args; + struct omdog_softc *sc = (struct omdog_softc *) self; + u_int32_t rev; + + sc->sc_iot = oa->oa_iot; + if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &sc->sc_ioh)) + panic("gptimer_attach: bus_space_map failed!"); + + rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, WIDR); + + printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); + omdog_sc = sc; +} + +void +omdog_wpending(int flags) +{ + struct omdog_softc *sc = omdog_sc; + while (bus_space_read_4(sc->sc_iot, sc->sc_ioh, WWPS) & flags) + ; +} + +void omdog_reset(void); /* XXX */ + +void +omdog_reset() +{ + if (omdog_sc == NULL) + return; + + bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WCRR, 0xffffff80); + omdog_wpending(WWPS_PEND_ALL); + + /* this sequence will start the watchdog. */ + bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WSPR, 0xbbbb); + omdog_wpending(WWPS_PEND_ALL); + bus_space_write_4(omdog_sc->sc_iot, omdog_sc->sc_ioh, WSPR, 0x4444); + omdog_wpending(WWPS_PEND_ALL); + delay(100000); +} diff --git a/sys/arch/armv7/omap/omehci.c b/sys/arch/armv7/omap/omehci.c new file mode 100644 index 00000000000..1fc17f84abc --- /dev/null +++ b/sys/arch/armv7/omap/omehci.c @@ -0,0 +1,487 @@ +/* $OpenBSD: omehci.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ + +/* + * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/*- + * Copyright (c) 2011 + * Ben Gray <ben.r.gray@gmail.com>. + * All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY AUTHOR AND CONTRIBUTORS ``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 AUTHOR OR CONTRIBUTORS 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 <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/rwlock.h> +#include <sys/timeout.h> + +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdivar.h> +#include <dev/usb/usb_mem.h> + +#include <armv7/omap/omapvar.h> +#include <armv7/omap/prcmvar.h> +#include <armv7/omap/omgpiovar.h> +#include <armv7/omap/omehcivar.h> + +#include <dev/usb/ehcireg.h> +#include <dev/usb/ehcivar.h> + +void omehci_attach(struct device *, struct device *, void *); +int omehci_detach(struct device *, int); +int omehci_activate(struct device *, int); + +struct omehci_softc { + struct ehci_softc sc; + void *sc_ih; + bus_space_handle_t uhh_ioh; + bus_space_handle_t tll_ioh; + + uint32_t ehci_rev; + uint32_t tll_avail; + + uint32_t port_mode[OMAP_HS_USB_PORTS]; + uint32_t phy_reset[OMAP_HS_USB_PORTS]; + uint32_t reset_gpio_pin[OMAP_HS_USB_PORTS]; + + void (*early_init)(void); +}; + +int omehci_init(struct omehci_softc *); +void omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port); +void omehci_enable(struct omehci_softc *); +void omehci_disable(struct omehci_softc *); +void omehci_utmi_init(struct omehci_softc *sc, unsigned int en_mask); +void misc_setup(struct omehci_softc *sc); +void omehci_phy_reset(uint32_t on, uint32_t _delay); +void omehci_uhh_init(struct omehci_softc *sc); +void omehci_v4_early_init(void); + +struct cfattach omehci_ca = { + sizeof (struct omehci_softc), NULL, omehci_attach, + omehci_detach, omehci_activate +}; + +void +omehci_attach(struct device *parent, struct device *self, void *aux) +{ + struct omehci_softc *sc = (struct omehci_softc *)self; + struct omap_attach_args *oa = aux; + usbd_status r; + char *devname = sc->sc.sc_bus.bdev.dv_xname; + uint32_t i; + + sc->sc.iot = oa->oa_iot; + sc->sc.sc_bus.dmatag = oa->oa_dmat; + sc->sc.sc_size = oa->oa_dev->mem[0].size; + + /* set defaults */ + for (i = 0; i < 3; i++) { + sc->phy_reset[i] = 0; + sc->port_mode[i] = EHCI_HCD_OMAP_MODE_UNKNOWN; + sc->reset_gpio_pin[i] = -1; + } + + switch (board_id) + { + case BOARD_ID_OMAP4_PANDA: + sc->tll_avail = 0; + sc->port_mode[0] = EHCI_HCD_OMAP_MODE_PHY; + sc->early_init = omehci_v4_early_init; + break; + default: + break; + } + + /* Map I/O space */ + if (bus_space_map(sc->sc.iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &sc->sc.ioh)) { + printf(": cannot map mem space\n"); + goto out; + } + + if (bus_space_map(sc->sc.iot, oa->oa_dev->mem[1].addr, + oa->oa_dev->mem[1].size, 0, &sc->uhh_ioh)) { + printf(": cannot map mem space\n"); + goto mem0; + } + + if (sc->tll_avail && + bus_space_map(sc->sc.iot, oa->oa_dev->mem[2].addr, + oa->oa_dev->mem[2].size, 0, &sc->tll_ioh)) { + printf(": cannot map mem space\n"); + goto mem1; + } + + printf("\n"); + + if (sc->early_init) + sc->early_init(); + + if (omehci_init(sc)) + return; + + /* Disable interrupts, so we don't get any spurious ones. */ + sc->sc.sc_offs = EREAD1(&sc->sc, EHCI_CAPLENGTH); + EOWRITE2(&sc->sc, EHCI_USBINTR, 0); + + sc->sc_ih = arm_intr_establish(oa->oa_dev->irq[0], IPL_USB, + ehci_intr, &sc->sc, devname); + if (sc->sc_ih == NULL) { + printf(": unable to establish interrupt\n"); + printf("XXX - disable ehci and prcm"); + goto mem2; + } + + strlcpy(sc->sc.sc_vendor, "TI OMAP", sizeof(sc->sc.sc_vendor)); + r = ehci_init(&sc->sc); + if (r != USBD_NORMAL_COMPLETION) { + printf("%s: init failed, error=%d\n", devname, r); + printf("XXX - disable ehci and prcm"); + goto intr; + } + + sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus, + usbctlprint); + + goto out; + +intr: + arm_intr_disestablish(sc->sc_ih); + sc->sc_ih = NULL; +mem2: + bus_space_unmap(sc->sc.iot, sc->tll_ioh, oa->oa_dev->mem[2].size); +mem1: + bus_space_unmap(sc->sc.iot, sc->uhh_ioh, oa->oa_dev->mem[1].size); +mem0: + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); + sc->sc.sc_size = 0; +out: + return; +} + +int +omehci_init(struct omehci_softc *sc) +{ + uint32_t i = 0, reg; + uint32_t reset_performed = 0; + uint32_t timeout = 0; + uint32_t tll_ch_mask = 0; + + /* enable high speed usb host clock */ + prcm_enablemodule(PRCM_USB); + + /* Hold the PHY in reset while configuring */ + for (i = 0; i < OMAP_HS_USB_PORTS; i++) { + if (sc->phy_reset[i]) { + /* Configure the GPIO to drive low (hold in reset) */ + if (sc->reset_gpio_pin[i] != -1) { + omgpio_set_dir(sc->reset_gpio_pin[i], + OMGPIO_DIR_OUT); + omgpio_clear_bit(sc->reset_gpio_pin[i]); + reset_performed = 1; + } + } + } + + /* Hold the PHY in RESET for enough time till DIR is high */ + if (reset_performed) + delay(10); + + /* Read the UHH revision */ + sc->ehci_rev = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, + OMAP_USBHOST_UHH_REVISION); + + /* Initilise the low level interface module(s) */ + if (sc->ehci_rev == OMAP_EHCI_REV1) { + /* Enable the USB TLL */ + prcm_enablemodule(PRCM_USBTLL); + + /* Perform TLL soft reset, and wait until reset is complete */ + bus_space_write_4(sc->sc.iot, sc->tll_ioh, + OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); + + /* Set the timeout to 100ms*/ + timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); + + /* Wait for TLL reset to complete */ + while ((bus_space_read_4(sc->sc.iot, sc->tll_ioh, + OMAP_USBTLL_SYSSTATUS) & TLL_SYSSTATUS_RESETDONE) + == 0x00) { + + /* Sleep for a tick */ + delay(10); + + if (timeout-- == 0) { + return 1; + } + } + + bus_space_write_4(sc->sc.iot, sc->tll_ioh, + OMAP_USBTLL_SYSCONFIG, + TLL_SYSCONFIG_ENAWAKEUP | TLL_SYSCONFIG_AUTOIDLE | + TLL_SYSCONFIG_SIDLE_SMART_IDLE | TLL_SYSCONFIG_CACTIVITY); + } else if (sc->ehci_rev == OMAP_EHCI_REV2) { + /* For OMAP44xx devices you have to enable the per-port clocks: + * PHY_MODE - External ULPI clock + * TTL_MODE - Internal UTMI clock + * HSIC_MODE - Internal 480Mhz and 60Mhz clocks + */ + if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) { + //ti_prcm_clk_set_source(USBP1_PHY_CLK, EXT_CLK); + prcm_enablemodule(PRCM_USBP1_PHY); + } else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) + prcm_enablemodule(PRCM_USBP1_UTMI); + else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) + prcm_enablemodule(PRCM_USBP1_HSIC); + + if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) { + //ti_prcm_clk_set_source(USBP2_PHY_CLK, EXT_CLK); + prcm_enablemodule(PRCM_USBP2_PHY); + } else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) + prcm_enablemodule(PRCM_USBP2_UTMI); + else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) + prcm_enablemodule(PRCM_USBP2_HSIC); + } + + /* Put UHH in SmartIdle/SmartStandby mode */ + reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, + OMAP_USBHOST_UHH_SYSCONFIG); + if (sc->ehci_rev == OMAP_EHCI_REV1) { + reg &= ~(UHH_SYSCONFIG_SIDLEMODE_MASK | + UHH_SYSCONFIG_MIDLEMODE_MASK); + reg |= (UHH_SYSCONFIG_ENAWAKEUP | + UHH_SYSCONFIG_AUTOIDLE | + UHH_SYSCONFIG_CLOCKACTIVITY | + UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE | + UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY); + } else if (sc->ehci_rev == OMAP_EHCI_REV2) { + reg &= ~UHH_SYSCONFIG_IDLEMODE_MASK; + reg |= UHH_SYSCONFIG_IDLEMODE_NOIDLE; + reg &= ~UHH_SYSCONFIG_STANDBYMODE_MASK; + reg |= UHH_SYSCONFIG_STANDBYMODE_NOSTDBY; + } + bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_SYSCONFIG, + reg); + + reg = bus_space_read_4(sc->sc.iot, sc->uhh_ioh, + OMAP_USBHOST_UHH_HOSTCONFIG); + + /* Setup ULPI bypass and burst configurations */ + reg |= (UHH_HOSTCONFIG_ENA_INCR4 | + UHH_HOSTCONFIG_ENA_INCR8 | + UHH_HOSTCONFIG_ENA_INCR16); + reg &= ~UHH_HOSTCONFIG_ENA_INCR_ALIGN; + + if (sc->ehci_rev == OMAP_EHCI_REV1) { + if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P1_CONNECT_STATUS; + if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P2_CONNECT_STATUS; + if (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_UNKNOWN) + reg &= ~UHH_HOSTCONFIG_P3_CONNECT_STATUS; + + /* Bypass the TLL module for PHY mode operation */ + if ((sc->port_mode[0] == EHCI_HCD_OMAP_MODE_PHY) || + (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_PHY) || + (sc->port_mode[2] == EHCI_HCD_OMAP_MODE_PHY)) + reg &= ~UHH_HOSTCONFIG_P1_ULPI_BYPASS; + else + reg |= UHH_HOSTCONFIG_P1_ULPI_BYPASS; + } else if (sc->ehci_rev == OMAP_EHCI_REV2) { + reg |= UHH_HOSTCONFIG_APP_START_CLK; + + /* Clear port mode fields for PHY mode*/ + reg &= ~UHH_HOSTCONFIG_P1_MODE_MASK; + reg &= ~UHH_HOSTCONFIG_P2_MODE_MASK; + + if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_TLL) + reg |= UHH_HOSTCONFIG_P1_MODE_UTMI_PHY; + else if (sc->port_mode[0] == EHCI_HCD_OMAP_MODE_HSIC) + reg |= UHH_HOSTCONFIG_P1_MODE_HSIC; + + if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_TLL) + reg |= UHH_HOSTCONFIG_P2_MODE_UTMI_PHY; + else if (sc->port_mode[1] == EHCI_HCD_OMAP_MODE_HSIC) + reg |= UHH_HOSTCONFIG_P2_MODE_HSIC; + } + + bus_space_write_4(sc->sc.iot, sc->uhh_ioh, OMAP_USBHOST_UHH_HOSTCONFIG, reg); + + /* If any of the ports are configured in TLL mode, enable them */ + for (i = 0; i < OMAP_HS_USB_PORTS; i++) + if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY) + tll_ch_mask |= 1 << i; + + /* Enable UTMI mode for required TLL channels */ +#ifdef notyet + if (tll_ch_mask) + omap_ehci_utmi_init(sc, tll_ch_mask); +#endif + + /* Release the PHY reset signal now we have configured everything */ + if (reset_performed) { + /* Delay for 10ms */ + delay(10000); + + /* Release reset */ + for (i = 0; i < 3; i++) { + if (sc->phy_reset[i] && (sc->reset_gpio_pin[i] != -1)) + omgpio_set_bit(sc->reset_gpio_pin[i]); + } + } + + /* Set the interrupt threshold control, it controls the maximum rate at + * which the host controller issues interrupts. We set it to 1 microframe + * at startup - the default is 8 mircoframes (equates to 1ms). + */ + reg = bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD); + reg &= 0xff00ffff; + reg |= (1 << 16); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_USBCMD, reg); + + /* Soft reset the PHY using PHY reset command over ULPI */ + for (i = 0; i < OMAP_HS_USB_PORTS; i++) + if (sc->port_mode[i] == EHCI_HCD_OMAP_MODE_PHY) + omehci_soft_phy_reset(sc, i); + + return(0); +} + +void +omehci_soft_phy_reset(struct omehci_softc *sc, unsigned int port) +{ + unsigned long timeout = (hz < 10) ? 1 : ((100 * hz) / 1000); + uint32_t reg; + + reg = ULPI_FUNC_CTRL_RESET + /* FUNCTION_CTRL_SET register */ + | (ULPI_SET(ULPI_FUNC_CTRL) << OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT) + /* Write */ + | (2 << OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT) + /* PORTn */ + | ((port + 1) << OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT) + /* start ULPI access*/ + | (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT); + + bus_space_write_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI, reg); + + timeout += 1000000; + /* Wait for ULPI access completion */ + while ((bus_space_read_4(sc->sc.iot, sc->sc.ioh, OMAP_USBHOST_INSNREG05_ULPI) + & (1 << OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT))) { + + /* Sleep for a tick */ + delay(10); + + if (timeout-- == 0) { + printf("PHY reset operation timed out\n"); + break; + } + } +} + +int +omehci_detach(struct device *self, int flags) +{ + struct omehci_softc *sc = (struct omehci_softc *)self; + int rv; + + rv = ehci_detach(&sc->sc, flags); + if (rv) + return (rv); + + if (sc->sc_ih != NULL) { + arm_intr_disestablish(sc->sc_ih); + sc->sc_ih = NULL; + } + + if (sc->sc.sc_size) { + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); + sc->sc.sc_size = 0; + } + + /* XXX: stop clock */ + + return (0); +} + +int +omehci_activate(struct device *self, int act) +{ + struct omehci_softc *sc = (struct omehci_softc *)self; + + switch (act) { + case DVACT_SUSPEND: + sc->sc.sc_bus.use_polling++; + /* FIXME */ + sc->sc.sc_bus.use_polling--; + break; + case DVACT_RESUME: + sc->sc.sc_bus.use_polling++; + /* FIXME */ + sc->sc.sc_bus.use_polling--; + break; + case DVACT_POWERDOWN: + ehci_reset(&sc->sc); + break; + } + return 0; +} + +void +omehci_v4_early_init() +{ + omgpio_set_dir(1, OMGPIO_DIR_OUT); + omgpio_clear_bit(1); + omgpio_set_dir(62, OMGPIO_DIR_OUT); + omgpio_clear_bit(62); + + /* wait for power down */ + delay(1000); + + omgpio_set_bit(1); + omgpio_set_bit(62); + + /* wait until powered up */ + delay(1000); +} diff --git a/sys/arch/armv7/omap/omehcivar.h b/sys/arch/armv7/omap/omehcivar.h new file mode 100644 index 00000000000..8eed72d4a5a --- /dev/null +++ b/sys/arch/armv7/omap/omehcivar.h @@ -0,0 +1,232 @@ +/* $OpenBSD: omehcivar.h,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ + +/* + * Misc + */ +#define OMAP_HS_USB_PORTS 3 + +/* + * USB TTL Module + */ +#define OMAP_USBTLL_REVISION 0x0000 +#define OMAP_USBTLL_SYSCONFIG 0x0010 +#define OMAP_USBTLL_SYSSTATUS 0x0014 +#define OMAP_USBTLL_IRQSTATUS 0x0018 +#define OMAP_USBTLL_IRQENABLE 0x001C +#define OMAP_USBTLL_TLL_SHARED_CONF 0x0030 +#define OMAP_USBTLL_TLL_CHANNEL_CONF(i) (0x0040 + (0x04 * (i))) +#define OMAP_USBTLL_SAR_CNTX(i) (0x0400 + (0x04 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_ID_LO(i) (0x0800 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_ID_HI(i) (0x0801 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_PRODUCT_ID_LO(i) (0x0802 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_PRODUCT_ID_HI(i) (0x0803 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_FUNCTION_CTRL(i) (0x0804 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_SET(i) (0x0805 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_FUNCTION_CTRL_CLR(i) (0x0806 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_INTERFACE_CTRL(i) (0x0807 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_SET(i) (0x0808 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_INTERFACE_CTRL_CLR(i) (0x0809 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_OTG_CTRL(i) (0x080A + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_OTG_CTRL_SET(i) (0x080B + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_OTG_CTRL_CLR(i) (0x080C + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE(i) (0x080D + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_SET(i) (0x080E + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_RISE_CLR(i) (0x080F + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL(i) (0x0810 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_SET(i) (0x0811 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_EN_FALL_CLR(i) (0x0812 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_STATUS(i) (0x0813 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_LATCH(i) (0x0814 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_DEBUG(i) (0x0815 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER(i) (0x0816 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_SET(i) (0x0817 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_SCRATCH_REGISTER_CLR(i) (0x0818 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_EXTENDED_SET_ACCESS(i) (0x082F + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN(i) (0x0830 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_SET(i) (0x0831 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_EN_CLR(i) (0x0832 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_STATUS(i) (0x0833 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VCONTROL_LATCH(i) (0x0834 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VSTATUS(i) (0x0835 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_SET(i) (0x0836 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_UTMI_VSTATUS_CLR(i) (0x0837 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_USB_INT_LATCH_NOCLR(i) (0x0838 + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_EN(i) (0x083B + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_SET(i) (0x083C + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_EN_CLR(i) (0x083D + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_STATUS(i) (0x083E + (0x100 * (i))) +#define OMAP_USBTLL_ULPI_VENDOR_INT_LATCH(i) (0x083F + (0x100 * (i))) + + +/* + * USB Host Module + */ + +/* UHH */ +#define OMAP_USBHOST_UHH_REVISION 0x0000 +#define OMAP_USBHOST_UHH_SYSCONFIG 0x0010 +#define OMAP_USBHOST_UHH_SYSSTATUS 0x0014 +#define OMAP_USBHOST_UHH_HOSTCONFIG 0x0040 +#define OMAP_USBHOST_UHH_DEBUG_CSR 0x0044 + +/* EHCI */ +#define OMAP_USBHOST_HCCAPBASE 0x0000 +#define OMAP_USBHOST_HCSPARAMS 0x0004 +#define OMAP_USBHOST_HCCPARAMS 0x0008 +#define OMAP_USBHOST_USBCMD 0x0010 +#define OMAP_USBHOST_USBSTS 0x0014 +#define OMAP_USBHOST_USBINTR 0x0018 +#define OMAP_USBHOST_FRINDEX 0x001C +#define OMAP_USBHOST_CTRLDSSEGMENT 0x0020 +#define OMAP_USBHOST_PERIODICLISTBASE 0x0024 +#define OMAP_USBHOST_ASYNCLISTADDR 0x0028 +#define OMAP_USBHOST_CONFIGFLAG 0x0050 +#define OMAP_USBHOST_PORTSC(i) (0x0054 + (0x04 * (i))) +#define OMAP_USBHOST_INSNREG00 0x0090 +#define OMAP_USBHOST_INSNREG01 0x0094 +#define OMAP_USBHOST_INSNREG02 0x0098 +#define OMAP_USBHOST_INSNREG03 0x009C +#define OMAP_USBHOST_INSNREG04 0x00A0 +#define OMAP_USBHOST_INSNREG05_UTMI 0x00A4 +#define OMAP_USBHOST_INSNREG05_ULPI 0x00A4 +#define OMAP_USBHOST_INSNREG06 0x00A8 +#define OMAP_USBHOST_INSNREG07 0x00AC +#define OMAP_USBHOST_INSNREG08 0x00B0 + +#define OMAP_USBHOST_INSNREG04_DISABLE_UNSUSPEND (1 << 5) + +#define OMAP_USBHOST_INSNREG05_ULPI_CONTROL_SHIFT 31 +#define OMAP_USBHOST_INSNREG05_ULPI_PORTSEL_SHIFT 24 +#define OMAP_USBHOST_INSNREG05_ULPI_OPSEL_SHIFT 22 +#define OMAP_USBHOST_INSNREG05_ULPI_REGADD_SHIFT 16 +#define OMAP_USBHOST_INSNREG05_ULPI_EXTREGADD_SHIFT 8 +#define OMAP_USBHOST_INSNREG05_ULPI_WRDATA_SHIFT 0 + + + + + +/* TLL Register Set */ +#define TLL_SYSCONFIG_CACTIVITY (1UL << 8) +#define TLL_SYSCONFIG_SIDLE_SMART_IDLE (2UL << 3) +#define TLL_SYSCONFIG_SIDLE_NO_IDLE (1UL << 3) +#define TLL_SYSCONFIG_SIDLE_FORCED_IDLE (0UL << 3) +#define TLL_SYSCONFIG_ENAWAKEUP (1UL << 2) +#define TLL_SYSCONFIG_SOFTRESET (1UL << 1) +#define TLL_SYSCONFIG_AUTOIDLE (1UL << 0) + +#define TLL_SYSSTATUS_RESETDONE (1UL << 0) + +#define TLL_SHARED_CONF_USB_90D_DDR_EN (1UL << 6) +#define TLL_SHARED_CONF_USB_180D_SDR_EN (1UL << 5) +#define TLL_SHARED_CONF_USB_DIVRATIO_MASK (7UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_128 (7UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_64 (6UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_32 (5UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_16 (4UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_8 (3UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_4 (2UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_2 (1UL << 2) +#define TLL_SHARED_CONF_USB_DIVRATIO_1 (0UL << 2) +#define TLL_SHARED_CONF_FCLK_REQ (1UL << 1) +#define TLL_SHARED_CONF_FCLK_IS_ON (1UL << 0) + +#define TLL_CHANNEL_CONF_DRVVBUS (1UL << 16) +#define TLL_CHANNEL_CONF_CHRGVBUS (1UL << 15) +#define TLL_CHANNEL_CONF_ULPINOBITSTUFF (1UL << 11) +#define TLL_CHANNEL_CONF_ULPIAUTOIDLE (1UL << 10) +#define TLL_CHANNEL_CONF_UTMIAUTOIDLE (1UL << 9) +#define TLL_CHANNEL_CONF_ULPIDDRMODE (1UL << 8) +#define TLL_CHANNEL_CONF_ULPIOUTCLKMODE (1UL << 7) +#define TLL_CHANNEL_CONF_TLLFULLSPEED (1UL << 6) +#define TLL_CHANNEL_CONF_TLLCONNECT (1UL << 5) +#define TLL_CHANNEL_CONF_TLLATTACH (1UL << 4) +#define TLL_CHANNEL_CONF_UTMIISADEV (1UL << 3) +#define TLL_CHANNEL_CONF_CHANEN (1UL << 0) + + +/* UHH Register Set */ +#define UHH_SYSCONFIG_MIDLEMODE_MASK (3UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_SMARTSTANDBY (2UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_NOSTANDBY (1UL << 12) +#define UHH_SYSCONFIG_MIDLEMODE_FORCESTANDBY (0UL << 12) +#define UHH_SYSCONFIG_CLOCKACTIVITY (1UL << 8) +#define UHH_SYSCONFIG_SIDLEMODE_MASK (3UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_SMARTIDLE (2UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_NOIDLE (1UL << 3) +#define UHH_SYSCONFIG_SIDLEMODE_FORCEIDLE (0UL << 3) +#define UHH_SYSCONFIG_ENAWAKEUP (1UL << 2) +#define UHH_SYSCONFIG_SOFTRESET (1UL << 1) +#define UHH_SYSCONFIG_AUTOIDLE (1UL << 0) + +#define UHH_HOSTCONFIG_APP_START_CLK (1UL << 31) +#define UHH_HOSTCONFIG_P3_CONNECT_STATUS (1UL << 10) +#define UHH_HOSTCONFIG_P2_CONNECT_STATUS (1UL << 9) +#define UHH_HOSTCONFIG_P1_CONNECT_STATUS (1UL << 8) +#define UHH_HOSTCONFIG_ENA_INCR_ALIGN (1UL << 5) +#define UHH_HOSTCONFIG_ENA_INCR16 (1UL << 4) +#define UHH_HOSTCONFIG_ENA_INCR8 (1UL << 3) +#define UHH_HOSTCONFIG_ENA_INCR4 (1UL << 2) +#define UHH_HOSTCONFIG_AUTOPPD_ON_OVERCUR_EN (1UL << 1) +#define UHH_HOSTCONFIG_P1_ULPI_BYPASS (1UL << 0) + +/* The following are on rev2 (OMAP44xx) of the EHCI only */ +#define UHH_SYSCONFIG_IDLEMODE_MASK (3UL << 2) +#define UHH_SYSCONFIG_IDLEMODE_NOIDLE (1UL << 2) +#define UHH_SYSCONFIG_STANDBYMODE_MASK (3UL << 4) +#define UHH_SYSCONFIG_STANDBYMODE_NOSTDBY (1UL << 4) + +#define UHH_HOSTCONFIG_P1_MODE_MASK (3UL << 16) +#define UHH_HOSTCONFIG_P1_MODE_ULPI_PHY (0UL << 16) +#define UHH_HOSTCONFIG_P1_MODE_UTMI_PHY (1UL << 16) +#define UHH_HOSTCONFIG_P1_MODE_HSIC (3UL << 16) +#define UHH_HOSTCONFIG_P2_MODE_MASK (3UL << 18) +#define UHH_HOSTCONFIG_P2_MODE_ULPI_PHY (0UL << 18) +#define UHH_HOSTCONFIG_P2_MODE_UTMI_PHY (1UL << 18) +#define UHH_HOSTCONFIG_P2_MODE_HSIC (3UL << 18) + +#define ULPI_FUNC_CTRL_RESET (1 << 5) + +/*-------------------------------------------------------------------------*/ + +/* + * Macros for Set and Clear + * See ULPI 1.1 specification to find the registers with Set and Clear offsets + */ +#define ULPI_SET(a) (a + 1) +#define ULPI_CLR(a) (a + 2) + +/*-------------------------------------------------------------------------*/ + +/* + * Register Map + */ +#define ULPI_VENDOR_ID_LOW 0x00 +#define ULPI_VENDOR_ID_HIGH 0x01 +#define ULPI_PRODUCT_ID_LOW 0x02 +#define ULPI_PRODUCT_ID_HIGH 0x03 +#define ULPI_FUNC_CTRL 0x04 +#define ULPI_IFC_CTRL 0x07 +#define ULPI_OTG_CTRL 0x0a +#define ULPI_USB_INT_EN_RISE 0x0d +#define ULPI_USB_INT_EN_FALL 0x10 +#define ULPI_USB_INT_STS 0x13 +#define ULPI_USB_INT_LATCH 0x14 +#define ULPI_DEBUG 0x15 +#define ULPI_SCRATCH 0x16 + +/* + * Values of UHH_REVISION - Note: these are not given in the TRM but taken + * from the linux OMAP EHCI driver (thanks guys). It has been verified on + * a Panda and Beagle board. + */ +#define OMAP_EHCI_REV1 0x00000010 /* OMAP3 */ +#define OMAP_EHCI_REV2 0x50700100 /* OMAP4 */ + +#define EHCI_VENDORID_OMAP3 0x42fa05 +#define OMAP_EHCI_HC_DEVSTR "TI OMAP USB 2.0 controller" + +#define EHCI_HCD_OMAP_MODE_UNKNOWN 0 +#define EHCI_HCD_OMAP_MODE_PHY 1 +#define EHCI_HCD_OMAP_MODE_TLL 2 +#define EHCI_HCD_OMAP_MODE_HSIC 3 diff --git a/sys/arch/armv7/omap/omgpio.c b/sys/arch/armv7/omap/omgpio.c new file mode 100644 index 00000000000..1f7ca3232ee --- /dev/null +++ b/sys/arch/armv7/omap/omgpio.c @@ -0,0 +1,641 @@ +/* $OpenBSD: omgpio.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ +/* + * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/queue.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/evcount.h> + +#include <arm/cpufunc.h> + +#include <machine/bus.h> +#include <machine/intr.h> + +#include <armv7/omap/omapvar.h> +#include <armv7/omap/omgpiovar.h> + +/* OMAP3 registers */ +#define GPIO3_REVISION 0x00 +#define GPIO3_SYSCONFIG 0x10 +#define GPIO3_SYSSTATUS 0x14 +#define GPIO3_IRQSTATUS1 0x18 +#define GPIO3_IRQENABLE1 0x1C +#define GPIO3_WAKEUPENABLE 0x20 +#define GPIO3_IRQSTATUS2 0x28 +#define GPIO3_IRQENABLE2 0x2C +#define GPIO3_CTRL 0x30 +#define GPIO3_OE 0x34 +#define GPIO3_DATAIN 0x38 +#define GPIO3_DATAOUT 0x3C +#define GPIO3_LEVELDETECT0 0x40 +#define GPIO3_LEVELDETECT1 0x44 +#define GPIO3_RISINGDETECT 0x48 +#define GPIO3_FALLINGDETECT 0x4C +#define GPIO3_DEBOUNCENABLE 0x50 +#define GPIO3_DEBOUNCINGTIME 0x54 +#define GPIO3_CLEARIRQENABLE1 0x60 +#define GPIO3_SETIRQENABLE1 0x64 +#define GPIO3_CLEARIRQENABLE2 0x70 +#define GPIO3_SETIRQENABLE2 0x74 +#define GPIO3_CLEARWKUENA 0x80 +#define GPIO3_SETWKUENA 0x84 +#define GPIO3_CLEARDATAOUT 0x90 +#define GPIO3_SETDATAOUT 0x94 +#define GPIO3_SIZE 0x100 + +/* OMAP4 registers */ +#define GPIO4_REVISION 0x00 +#define GPIO4_SYSCONFIG 0x10 +#define GPIO4_IRQSTATUS_RAW_0 0x24 +#define GPIO4_IRQSTATUS_RAW_1 0x28 +#define GPIO4_IRQSTATUS_0 0x2C +#define GPIO4_IRQSTATUS_1 0x30 +#define GPIO4_IRQSTATUS_SET_0 0x34 +#define GPIO4_IRQSTATUS_SET_1 0x38 +#define GPIO4_IRQSTATUS_CLR_0 0x3C +#define GPIO4_IRQSTATUS_CLR_1 0x40 +#define GPIO4_IRQWAKEN_0 0x44 +#define GPIO4_IRQWAKEN_1 0x48 +#define GPIO4_SYSSTATUS 0x114 +#define GPIO4_IRQSTATUS1 0x118 +#define GPIO4_IRQENABLE1 0x11C +#define GPIO4_WAKEUPENABLE 0x120 +#define GPIO4_IRQSTATUS2 0x128 +#define GPIO4_IRQENABLE2 0x12C +#define GPIO4_CTRL 0x130 +#define GPIO4_OE 0x134 +#define GPIO4_DATAIN 0x138 +#define GPIO4_DATAOUT 0x13C +#define GPIO4_LEVELDETECT0 0x140 +#define GPIO4_LEVELDETECT1 0x144 +#define GPIO4_RISINGDETECT 0x148 +#define GPIO4_FALLINGDETECT 0x14C +#define GPIO4_DEBOUNCENABLE 0x150 +#define GPIO4_DEBOUNCINGTIME 0x154 +#define GPIO4_CLEARIRQENABLE1 0x160 +#define GPIO4_SETIRQENABLE1 0x164 +#define GPIO4_CLEARIRQENABLE2 0x170 +#define GPIO4_SETIRQENABLE2 0x174 +#define GPIO4_CLEARWKUPENA 0x180 +#define GPIO4_SETWKUENA 0x184 +#define GPIO4_CLEARDATAOUT 0x190 +#define GPIO4_SETDATAOUT 0x194 + +#define GPIO_NUM_PINS 32 + +struct intrhand { + int (*ih_func)(void *); /* handler */ + void *ih_arg; /* arg for handler */ + int ih_ipl; /* IPL_* */ + int ih_irq; /* IRQ number */ + int ih_gpio; /* gpio pin */ + struct evcount ih_count; + char *ih_name; +}; + +struct omgpio_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + void *sc_ih_h; + void *sc_ih_l; + int sc_max_il; + int sc_min_il; + int sc_irq; + struct intrhand *sc_handlers[GPIO_NUM_PINS]; + int sc_omap_ver; + unsigned int (*sc_get_bit)(struct omgpio_softc *sc, + unsigned int gpio); + void (*sc_set_bit)(struct omgpio_softc *sc, + unsigned int gpio); + void (*sc_clear_bit)(struct omgpio_softc *sc, + unsigned int gpio); + void (*sc_set_dir)(struct omgpio_softc *sc, + unsigned int gpio, unsigned int dir); +}; + +#define GPIO_PIN_TO_INST(x) ((x) >> 5) +#define GPIO_PIN_TO_OFFSET(x) ((x) & 0x1f) + +int omgpio_match(struct device *parent, void *v, void *aux); +void omgpio_attach(struct device *parent, struct device *self, void *args); +void omgpio_recalc_interrupts(struct omgpio_softc *sc); +int omgpio_irq(void *); +int omgpio_irq_dummy(void *); + +unsigned int omgpio_v3_get_bit(struct omgpio_softc *, unsigned int); +void omgpio_v3_set_bit(struct omgpio_softc *, unsigned int); +void omgpio_v3_clear_bit(struct omgpio_softc *, unsigned int); +void omgpio_v3_set_dir(struct omgpio_softc *, unsigned int , unsigned int); +unsigned int omgpio_v4_get_bit(struct omgpio_softc *, unsigned int); +void omgpio_v4_set_bit(struct omgpio_softc *, unsigned int); +void omgpio_v4_clear_bit(struct omgpio_softc *, unsigned int); +void omgpio_v4_set_dir(struct omgpio_softc *, unsigned int, unsigned int); +unsigned int omgpio_v4_get_dir(struct omgpio_softc *, unsigned int); + + +struct cfattach omgpio_ca = { + sizeof (struct omgpio_softc), omgpio_match, omgpio_attach +}; + +struct cfdriver omgpio_cd = { + NULL, "omgpio", DV_DULL +}; + +int +omgpio_match(struct device *parent, void *v, void *aux) +{ + switch (board_id) { + case BOARD_ID_OMAP3_BEAGLE: + case BOARD_ID_OMAP3_OVERO: + break; /* continue trying */ + case BOARD_ID_OMAP4_PANDA: + break; /* continue trying */ + default: + return 0; /* unknown */ + } + return (1); +} + +void +omgpio_attach(struct device *parent, struct device *self, void *args) +{ + struct omap_attach_args *oa = args; + struct omgpio_softc *sc = (struct omgpio_softc *) self; + u_int32_t rev; + + sc->sc_iot = oa->oa_iot; + if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &sc->sc_ioh)) + panic("omgpio_attach: bus_space_map failed!"); + + + switch (board_id) { + case BOARD_ID_OMAP3_BEAGLE: + case BOARD_ID_OMAP3_OVERO: + sc->sc_omap_ver = 3; + sc->sc_get_bit = omgpio_v3_get_bit; + sc->sc_set_bit = omgpio_v3_set_bit; + sc->sc_clear_bit = omgpio_v3_clear_bit; + sc->sc_set_dir = omgpio_v3_set_dir; + break; + case BOARD_ID_OMAP4_PANDA: + sc->sc_omap_ver = 4; + sc->sc_get_bit = omgpio_v4_get_bit; + sc->sc_set_bit = omgpio_v4_set_bit; + sc->sc_clear_bit = omgpio_v4_clear_bit; + sc->sc_set_dir = omgpio_v4_set_dir; + break; + } + + rev = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_REVISION); + + printf(" omap%d rev %d.%d\n", sc->sc_omap_ver, rev >> 4 & 0xf, + rev & 0xf); + + sc->sc_irq = oa->oa_dev->irq[0]; + + if (sc->sc_omap_ver == 3) { + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + GPIO3_CLEARIRQENABLE1, ~0); + } else if (sc->sc_omap_ver == 4) { + /* XXX - nothing? */ + } + + /* XXX - SYSCONFIG */ + /* XXX - CTRL */ + /* XXX - DEBOUNCE */ +} + +/* XXX - This assumes MCU INTERRUPTS are IRQ1, and DSP are IRQ2 */ + +#if 0 +/* XXX - FIND THESE REGISTERS !!! */ +unsigned int +omgpio_get_function(unsigned int gpio, unsigned int fn) +{ + return 0; +} + +void +omgpio_set_function(unsigned int gpio, unsigned int fn) +{ +} +#endif + +/* + * get_bit() is not reliable if used on an output pin. + */ + +unsigned int +omgpio_get_bit(unsigned int gpio) +{ + struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; + + return sc->sc_get_bit(sc, gpio); +} + +void +omgpio_set_bit(unsigned int gpio) +{ + struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; + + sc->sc_set_bit(sc, gpio); +} + +void +omgpio_clear_bit(unsigned int gpio) +{ + struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; + + sc->sc_clear_bit(sc, gpio); +} +void +omgpio_set_dir(unsigned int gpio, unsigned int dir) +{ + struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; + + sc->sc_set_dir(sc, gpio, dir); +} + +unsigned int +omgpio_v3_get_bit(struct omgpio_softc *sc, unsigned int gpio) +{ + u_int32_t reg; + + reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_DATAIN); + return (reg >> GPIO_PIN_TO_OFFSET(gpio)) & 0x1; +} + +void +omgpio_v3_set_bit(struct omgpio_softc *sc, unsigned int gpio) +{ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_SETDATAOUT, + 1 << GPIO_PIN_TO_OFFSET(gpio)); +} + +void +omgpio_v3_clear_bit(struct omgpio_softc *sc, unsigned int gpio) +{ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_CLEARDATAOUT, + 1 << GPIO_PIN_TO_OFFSET(gpio)); +} + +void +omgpio_v3_set_dir(struct omgpio_softc *sc, unsigned int gpio, unsigned int dir) +{ + int s; + u_int32_t reg; + + s = splhigh(); + + reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_DATAIN); + if (dir == OMGPIO_DIR_IN) + reg |= 1 << GPIO_PIN_TO_OFFSET(gpio); + else + reg &= ~(1 << GPIO_PIN_TO_OFFSET(gpio)); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_OE, reg); + + splx(s); +} + +unsigned int +omgpio_v4_get_bit(struct omgpio_softc *sc, unsigned int gpio) +{ + u_int32_t reg; + + if(omgpio_v4_get_dir(sc, gpio) == OMGPIO_DIR_IN) + reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO4_DATAIN); + else + reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO4_DATAOUT); + return (reg >> GPIO_PIN_TO_OFFSET(gpio)) & 0x1; +} + +void +omgpio_v4_set_bit(struct omgpio_softc *sc, unsigned int gpio) +{ + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO4_SETDATAOUT, + 1 << GPIO_PIN_TO_OFFSET(gpio)); +} + +void +omgpio_v4_clear_bit(struct omgpio_softc *sc, unsigned int gpio) +{ + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO4_CLEARDATAOUT, + 1 << GPIO_PIN_TO_OFFSET(gpio)); +} + +void +omgpio_v4_set_dir(struct omgpio_softc *sc, unsigned int gpio, unsigned int dir) +{ + int s; + u_int32_t reg; + + s = splhigh(); + + reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO4_OE); + if (dir == OMGPIO_DIR_IN) + reg |= 1 << GPIO_PIN_TO_OFFSET(gpio); + else + reg &= ~(1 << GPIO_PIN_TO_OFFSET(gpio)); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO4_OE, reg); + + splx(s); +} + +unsigned int +omgpio_v4_get_dir(struct omgpio_softc *sc, unsigned int gpio) +{ + int s; + u_int32_t dir, reg; + + s = splhigh(); + + reg = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO4_OE); + if (reg & (1 << GPIO_PIN_TO_OFFSET(gpio))) + dir = OMGPIO_DIR_IN; + else + dir = OMGPIO_DIR_OUT; + + splx(s); + + return dir; +} + +#if 0 +void +omgpio_clear_intr(struct omgpio_softc *sc, unsigned int gpio) +{ + struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_IRQSTATUS1, + 1 << GPIO_PIN_TO_OFFSET(gpio)); +} + +void +omgpio_intr_mask(struct omgpio_softc *sc, unsigned int gpio) +{ + struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_CLEARIRQENABLE1, + 1 << GPIO_PIN_TO_OFFSET(gpio)); +} + +void +omgpio_intr_unmask(struct omgpio_softc *sc, unsigned int gpio) +{ + struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_SETIRQENABLE1, + 1 << GPIO_PIN_TO_OFFSET(gpio)); +} + +void +omgpio_intr_level(struct omgpio_softc *sc, unsigned int gpio, unsigned int level) +{ + u_int32_t fe, re, l0, l1, bit; + struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; + int s; + + s = splhigh(); + + fe = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_FALLINGDETECT); + re = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_RISINGDETECT); + l0 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_LEVELDETECT0); + l1 = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_LEVELDETECT1); + + bit = 1 << GPIO_PIN_TO_OFFSET(gpio); + + switch (level) { + case IST_NONE: + fe &= ~bit; + re &= ~bit; + l0 &= ~bit; + l1 &= ~bit; + break; + case IST_EDGE_FALLING: + fe |= bit; + re &= ~bit; + l0 &= ~bit; + l1 &= ~bit; + break; + case IST_EDGE_RISING: + fe &= ~bit; + re |= bit; + l0 &= ~bit; + l1 &= ~bit; + break; + case IST_PULSE: /* XXX */ + /* FALLTHRU */ + case IST_EDGE_BOTH: + fe |= bit; + re |= bit; + l0 &= ~bit; + l1 &= ~bit; + break; + case IST_LEVEL_LOW: + fe &= ~bit; + re &= ~bit; + l0 |= bit; + l1 &= ~bit; + break; + case IST_LEVEL_HIGH: + fe &= ~bit; + re &= ~bit; + l0 &= ~bit; + l1 |= bit; + break; + default: + panic("omgpio_intr_level: bad level: %d", level); + break; + } + + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_FALLINGDETECT, fe); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_RISINGDETECT, re); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_LEVELDETECT0, l0); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, GPIO3_LEVELDETECT1, l1); + + splx(s); +} + +void * +omgpio_intr_establish(struct omgpio_softc *sc, unsigned int gpio, int level, int spl, + int (*func)(void *), void *arg, char *name) +{ + int psw; + struct intrhand *ih; + struct omgpio_softc *sc; + + /* + * XXX - is gpio here the pin or the interrupt number + * which is 96 + gpio pin? + */ + + if (GPIO_PIN_TO_INST(gpio) > omgpio_cd.cd_ndevs) + panic("omgpio_intr_establish: bogus irqnumber %d: %s", + gpio, name); + + sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(gpio)]; + + if (sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] != NULL) + panic("omgpio_intr_establish: gpio pin busy %d old %s new %s", + gpio, sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)]->ih_name, + name); + + psw = disable_interrupts(I32_bit); + + /* no point in sleeping unless someone can free memory. */ + ih = (struct intrhand *)malloc( sizeof *ih, M_DEVBUF, + cold ? M_NOWAIT : M_WAITOK); + if (ih == NULL) + panic("intr_establish: can't malloc handler info"); + ih->ih_func = func; + ih->ih_arg = arg; + ih->ih_ipl = level; + ih->ih_gpio = gpio; + ih->ih_irq = gpio + 512; + ih->ih_name = name; + + sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] = ih; + + evcount_attach(&ih->ih_count, name, &ih->ih_irq); + + omgpio_intr_level(gpio, level); + omgpio_intr_unmask(gpio); + + omgpio_recalc_interrupts(sc); + + restore_interrupts(psw); + + return (ih); +} + +void +omgpio_intr_disestablish(struct omgpio_softc *sc, void *cookie) +{ + int psw; + struct intrhand *ih = cookie; + struct omgpio_softc *sc = omgpio_cd.cd_devs[GPIO_PIN_TO_INST(ih->ih_gpio)]; + int gpio = ih->ih_gpio; + psw = disable_interrupts(I32_bit); + + ih = sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)]; + sc->sc_handlers[GPIO_PIN_TO_OFFSET(gpio)] = NULL; + + evcount_detach(&ih->ih_count); + + free(ih, M_DEVBUF); + + omgpio_intr_level(gpio, IST_NONE); + omgpio_intr_mask(gpio); + omgpio_clear_intr(gpio); /* Just in case */ + + omgpio_recalc_interrupts(sc); + + restore_interrupts(psw); +} + +int +omgpio_irq(void *v) +{ + struct omgpio_softc *sc = v; + u_int32_t pending; + struct intrhand *ih; + int bit; + + pending = bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_IRQSTATUS1); + + while (pending != 0) { + bit = ffs(pending) - 1; + ih = sc->sc_handlers[bit]; + + if (ih != NULL) { + if (ih->ih_func(ih->ih_arg)) + ih->ih_count.ec_count++; + omgpio_clear_intr(ih->ih_gpio); + } else { + panic("omgpio: irq fired no handler, gpio %x %x %x", + sc->sc_dev.dv_unit * 32 + bit, pending, + bus_space_read_4(sc->sc_iot, sc->sc_ioh, GPIO3_IRQENABLE1) + + ); + } + pending &= ~(1 << bit); + } + return 1; +} + +int +omgpio_irq_dummy(void *v) +{ + return 0; +} + +void +omgpio_recalc_interrupts(struct omgpio_softc *sc) +{ + struct intrhand *ih; + int max = IPL_NONE; + int min = IPL_HIGH; + int i; + + for (i = 0; i < GPIO_NUM_PINS; i++) { + ih = sc->sc_handlers[i]; + if (ih != NULL) { + if (ih->ih_ipl > max) + max = ih->ih_ipl; + + if (ih->ih_ipl < min) + min = ih->ih_ipl; + } + } + if (max == IPL_NONE) + min = IPL_NONE; + +#if 0 + if ((max == IPL_NONE || max != sc->sc_max_il) && sc->sc_ih_h != NULL) + arm_intr_disestablish(sc->sc_ih_h); + + if (max != IPL_NONE && max != sc->sc_max_il) { + sc->sc_ih_h = arm_intr_establish(sc->sc_irq, max, omgpio_irq, + sc, NULL); + } +#else + if (sc->sc_ih_h != NULL) + arm_intr_disestablish(sc->sc_ih_h); + + if (max != IPL_NONE) { + sc->sc_ih_h = arm_intr_establish(sc->sc_irq, max, omgpio_irq, + sc, NULL); + } +#endif + + sc->sc_max_il = max; + + if (sc->sc_ih_l != NULL) + arm_intr_disestablish(sc->sc_ih_l); + + if (max != min) { + sc->sc_ih_h = arm_intr_establish(sc->sc_irq, min, + omgpio_irq_dummy, sc, NULL); + } + sc->sc_min_il = min; +} +#endif diff --git a/sys/arch/armv7/omap/omgpiovar.h b/sys/arch/armv7/omap/omgpiovar.h new file mode 100644 index 00000000000..1a47dd948a9 --- /dev/null +++ b/sys/arch/armv7/omap/omgpiovar.h @@ -0,0 +1,40 @@ +/* $OpenBSD: omgpiovar.h,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ +/* + * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#ifndef OMGPIOVAR_H +#define OMGPIOVAR_H + +#define OMGPIO_DIR_IN 0 +#define OMGPIO_DIR_OUT 1 + +unsigned int omgpio_get_function(unsigned int gpio, unsigned int fn); +void omgpio_set_function(unsigned int gpio, unsigned int fn); +unsigned int omgpio_get_bit(unsigned int gpio); +void omgpio_set_bit(unsigned int gpio); +void omgpio_clear_bit(unsigned int gpio); +void omgpio_set_dir(unsigned int gpio, unsigned int dir); + +/* interrupts */ +void omgpio_clear_intr(unsigned int gpio); +void omgpio_intr_mask(unsigned int gpio); +void omgpio_intr_unmask(unsigned int gpio); +void omgpio_intr_level(unsigned int gpio, unsigned int level); +void *omgpio_intr_establish(unsigned int gpio, int level, int spl, + int (*func)(void *), void *arg, char *name); +void omgpio_intr_disestablish(void *cookie); + +#endif /* OMGPIOVAR_H */ diff --git a/sys/arch/armv7/omap/ommmc.c b/sys/arch/armv7/omap/ommmc.c new file mode 100644 index 00000000000..ccb12ff9206 --- /dev/null +++ b/sys/arch/armv7/omap/ommmc.c @@ -0,0 +1,1232 @@ +/* $OpenBSD: ommmc.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ + +/* + * Copyright (c) 2009 Dale Rahn <drahn@openbsd.org> + * Copyright (c) 2006 Uwe Stuehler <uwe@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/* Omap SD/MMC support derived from /sys/dev/sdmmc/sdhc.c */ + + +#include <sys/param.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/kthread.h> +#include <sys/malloc.h> +#include <sys/systm.h> +#include <machine/bus.h> + +#include <dev/sdmmc/sdmmcchip.h> +#include <dev/sdmmc/sdmmcvar.h> + +#include <armv7/omap/omapvar.h> +#include <armv7/omap/prcmvar.h> + +/* + * NOTE: on OMAP4430/AM335x these registers skew by 0x100 + * this is handled by mapping at base address + 0x100 + */ +/* registers */ +#define MMCHS_SYSCONFIG 0x010 +#define MMCHS_SYSSTATUS 0x014 +#define MMCHS_CSRE 0x024 +#define MMCHS_SYSTEST 0x028 +#define MMCHS_CON 0x02C +#define MMCHS_CON_INIT (1<<1) +#define MMCHS_PWCNT 0x030 +#define MMCHS_BLK 0x104 +#define MMCHS_BLK_NBLK_MAX 0xffff +#define MMCHS_BLK_NBLK_SHIFT 16 +#define MMCHS_BLK_NBLK_MASK (MMCHS_BLK_NBLK_MAX<<MMCHS_BLK_NBLK_SHIFT) +#define MMCHS_BLK_BLEN_MAX 0x400 +#define MMCHS_BLK_BLEN_SHIFT 0 +#define MMCHS_BLK_BLEN_MASK (MMCHS_BLK_BLEN_MAX<<MMCHS_BLK_BLEN_SHIFT) +#define MMCHS_ARG 0x108 +#define MMCHS_CMD 0x10C +#define MMCHS_CMD_INDX_SHIFT 24 +#define MMCHS_CMD_INDX_SHIFT_MASK (0x3f << MMCHS_CMD_INDX_SHIFT) +#define MMCHS_CMD_CMD_TYPE_SHIFT 22 +#define MMCHS_CMD_DP_SHIFT 21 +#define MMCHS_CMD_DP (1 << MMCHS_CMD_DP_SHIFT) +#define MMCHS_CMD_CICE_SHIFT 20 +#define MMCHS_CMD_CICE (1 << MMCHS_CMD_CICE_SHIFT) +#define MMCHS_CMD_CCCE_SHIFT 19 +#define MMCHS_CMD_CCCE (1 << MMCHS_CMD_CCCE_SHIFT) +#define MMCHS_CMD_RSP_TYPE_SHIFT 16 +#define MMCHS_CMD_RESP_NONE (0x0 << MMCHS_CMD_RSP_TYPE_SHIFT) +#define MMCHS_CMD_RESP136 (0x1 << MMCHS_CMD_RSP_TYPE_SHIFT) +#define MMCHS_CMD_RESP48 (0x2 << MMCHS_CMD_RSP_TYPE_SHIFT) +#define MMCHS_CMD_RESP48B (0x3 << MMCHS_CMD_RSP_TYPE_SHIFT) +#define MMCHS_CMD_MSBS (1 << 5) +#define MMCHS_CMD_DDIR (1 << 4) +#define MMCHS_CMD_ACEN (1 << 2) +#define MMCHS_CMD_BCE (1 << 1) +#define MMCHS_CMD_DE (1 << 0) +#define MMCHS_RSP10 0x110 +#define MMCHS_RSP32 0x114 +#define MMCHS_RSP54 0x118 +#define MMCHS_RSP76 0x11C +#define MMCHS_DATA 0x120 +#define MMCHS_PSTATE 0x124 +#define MMCHS_PSTATE_CLEV (1<<24) +#define MMCHS_PSTATE_DLEV_SH 20 +#define MMCHS_PSTATE_DLEV_M (0xf << MMCHS_PSTATE_DLEV_SH) +#define MMCHS_PSTATE_BRE (1<<11) +#define MMCHS_PSTATE_BWE (1<<10) +#define MMCHS_PSTATE_RTA (1<<9) +#define MMCHS_PSTATE_WTA (1<<8) +#define MMCHS_PSTATE_DLA (1<<2) +#define MMCHS_PSTATE_DATI (1<<1) +#define MMCHS_PSTATE_CMDI (1<<0) +#define MMCHS_PSTATE_FMT "\20" \ + "\x098_CLEV" \ + "\x08b_BRE" \ + "\x08a_BWE" \ + "\x089_RTA" \ + "\x088_WTA" \ + "\x082_DLA" \ + "\x081_DATI" \ + "\x080_CMDI" +#define MMCHS_HCTL 0x128 +#define MMCHS_HCTL_SDVS_SHIFT 9 +#define MMCHS_HCTL_SDVS_MASK (0x7<<MMCHS_HCTL_SDVS_SHIFT) +#define MMCHS_HCTL_SDVS_V18 (0x5<<MMCHS_HCTL_SDVS_SHIFT) +#define MMCHS_HCTL_SDVS_V30 (0x6<<MMCHS_HCTL_SDVS_SHIFT) +#define MMCHS_HCTL_SDVS_V33 (0x7<<MMCHS_HCTL_SDVS_SHIFT) +#define MMCHS_HCTL_SDBP (1<<8) +#define MMCHS_HCTL_DTW (1<<1) +#define MMCHS_SYSCTL 0x12C +#define MMCHS_SYSCTL_SRD (1<<26) +#define MMCHS_SYSCTL_SRC (1<<25) +#define MMCHS_SYSCTL_SRA (1<<24) +#define MMCHS_SYSCTL_DTO_SH 16 +#define MMCHS_SYSCTL_DTO_MASK 0x000f0000 +#define MMCHS_SYSCTL_CLKD_SH 6 +#define MMCHS_SYSCTL_CLKD_MASK 0x0000ffc0 +#define MMCHS_SYSCTL_CEN (1<<2) +#define MMCHS_SYSCTL_ICS (1<<1) +#define MMCHS_SYSCTL_ICE (1<<0) +#define MMCHS_STAT 0x130 +#define MMCHS_STAT_BADA (1<<29) +#define MMCHS_STAT_CERR (1<<28) +#define MMCHS_STAT_ACE (1<<24) +#define MMCHS_STAT_DEB (1<<22) +#define MMCHS_STAT_DCRC (1<<21) +#define MMCHS_STAT_DTO (1<<20) +#define MMCHS_STAT_CIE (1<<19) +#define MMCHS_STAT_CEB (1<<18) +#define MMCHS_STAT_CCRC (1<<17) +#define MMCHS_STAT_CTO (1<<16) +#define MMCHS_STAT_ERRI (1<<15) +#define MMCHS_STAT_OBI (1<<9) +#define MMCHS_STAT_CIRQ (1<<8) +#define MMCHS_STAT_BRR (1<<5) +#define MMCHS_STAT_BWR (1<<4) +#define MMCHS_STAT_BGE (1<<2) +#define MMCHS_STAT_TC (1<<1) +#define MMCHS_STAT_CC (1<<0) +#define MMCHS_STAT_FMT "\20" \ + "\x09d_BADA" \ + "\x09c_CERR" \ + "\x098_ACE" \ + "\x096_DEB" \ + "\x095_DCRC" \ + "\x094_DTO" \ + "\x093_CIE" \ + "\x092_CEB" \ + "\x091_CCRC" \ + "\x090_CTO" \ + "\x08f_ERRI" \ + "\x089_OBI" \ + "\x088_CIRQ" \ + "\x085_BRR" \ + "\x084_BWR" \ + "\x082_BGE" \ + "\x081_TC" \ + "\x080_CC" +#define MMCHS_IE 0x134 +#define MMCHS_ISE 0x138 +#define MMCHS_AC12 0x13C +#define MMCHS_CAPA 0x140 +#define MMCHS_CAPA_VS18 (1 << 26) +#define MMCHS_CAPA_VS30 (1 << 25) +#define MMCHS_CAPA_VS33 (1 << 24) +#define MMCHS_CAPA_SRS (1 << 23) +#define MMCHS_CAPA_DS (1 << 22) +#define MMCHS_CAPA_HSS (1 << 21) +#define MMCHS_CAPA_MBL_SHIFT 16 +#define MMCHS_CAPA_MBL_MASK (3 << MMCHS_CAPA_MBL_SHIFT) +#define MMCHS_CUR_CAPA 0x148 +#define MMCHS_REV 0x1fc + +#define SDHC_COMMAND_TIMEOUT hz +#define SDHC_BUFFER_TIMEOUT hz +#define SDHC_TRANSFER_TIMEOUT hz + +void ommmc_attach(struct device *parent, struct device *self, void *args); + +struct ommmc_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; + void *sc_ih; /* Interrupt handler */ + u_int sc_flags; + + struct device *sdmmc; /* generic SD/MMC device */ + int clockbit; /* clock control bit */ + u_int clkbase; /* base clock frequency in KHz */ + int maxblklen; /* maximum block length */ + int flags; /* flags for this host */ + uint32_t ocr; /* OCR value from capabilities */ +// u_int8_t regs[14]; /* host controller state */ + uint32_t intr_status; /* soft interrupt status */ + uint32_t intr_error_status; /* */ +}; + + +/* Host controller functions called by the attachment driver. */ +int ommmc_host_found(struct ommmc_softc *, bus_space_tag_t, + bus_space_handle_t, bus_size_t, int); +void ommmc_power(int, void *); +void ommmc_shutdown(void *); +int ommmc_intr(void *); + +/* RESET MODES */ +#define MMC_RESET_DAT 1 +#define MMC_RESET_CMD 2 +#define MMC_RESET_ALL (MMC_RESET_CMD|MMC_RESET_DAT) + +#define HDEVNAME(sc) ((sc)->sc_dev.dv_xname) + +/* flag values */ +#define SHF_USE_DMA 0x0001 + +/* MMCHS should only be accessed with 4 byte reads or writes. */ +#if 0 +struct regtbl { + char* name; + uint32_t reg; +} tblname[] = { + {"MMCHS_SYSCONFIG", MMCHS_SYSCONFIG}, + {"MMCHS_SYSSTATUS", MMCHS_SYSSTATUS}, + {"MMCHS_CSRE", MMCHS_CSRE}, + {"MMCHS_SYSTEST", MMCHS_SYSTEST}, + {"MMCHS_CON", MMCHS_CON}, + {"MMCHS_PWCNT", MMCHS_PWCNT}, + {"MMCHS_BLK", MMCHS_BLK}, + {"MMCHS_ARG", MMCHS_ARG}, + {"MMCHS_CMD", MMCHS_CMD}, + {"MMCHS_RSP10", MMCHS_RSP10}, + {"MMCHS_RSP32", MMCHS_RSP32}, + {"MMCHS_RSP54", MMCHS_RSP54}, + {"MMCHS_RSP76", MMCHS_RSP76}, + {"MMCHS_DATA", MMCHS_DATA}, + {"MMCHS_PSTATE", MMCHS_PSTATE}, + {"MMCHS_HCTL", MMCHS_HCTL}, + {"MMCHS_SYSCTL", MMCHS_SYSCTL}, + {"MMCHS_STAT", MMCHS_STAT}, + {"MMCHS_IE", MMCHS_IE}, + {"MMCHS_ISE", MMCHS_ISE}, + {"MMCHS_AC12", MMCHS_AC12}, + {"MMCHS_CAPA", MMCHS_CAPA}, + {"MMCHS_CUR_CAPA", MMCHS_CUR_CAPA}, + {NULL, 0 } +}; +uint32_t HREAD4(struct ommmc_softc *sc, uint32_t reg); +void HWRITE4(struct ommmc_softc *sc, uint32_t reg, uint32_t val); +uint32_t HREAD4(struct ommmc_softc *sc, uint32_t reg) +{ + uint32_t val; + int i; + char *regname = "???"; + for (i = 0; tblname[i].name != NULL; i++) { + if (tblname[i].reg == reg) { + regname = tblname[i].name; + break; + } + } + val = (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))); + printf("read reg[%s] = %x\n", regname, val); + return val; + +} +void HWRITE4(struct ommmc_softc *sc, uint32_t reg, uint32_t val) +{ + char *regname = "???"; + int i; + for (i = 0; tblname[i].name != NULL; i++) { + if (tblname[i].reg == reg) { + regname = tblname[i].name; + break; + } + } + printf("write reg[%s] = %x\n", regname, val); + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)); +} +#define HSET4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) +#define HCLR4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) +#else +#define HREAD4(sc, reg) \ + (bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg))) +#define HWRITE4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) +#define HSET4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) | (bits)) +#define HCLR4(sc, reg, bits) \ + HWRITE4((sc), (reg), HREAD4((sc), (reg)) & ~(bits)) +#endif + +int ommmc_host_reset(sdmmc_chipset_handle_t); +uint32_t ommmc_host_ocr(sdmmc_chipset_handle_t); +int ommmc_host_maxblklen(sdmmc_chipset_handle_t); +int ommmc_card_detect(sdmmc_chipset_handle_t); +int ommmc_bus_power(sdmmc_chipset_handle_t, uint32_t); +int ommmc_bus_clock(sdmmc_chipset_handle_t, int); +void ommmc_card_intr_mask(sdmmc_chipset_handle_t, int); +void ommmc_card_intr_ack(sdmmc_chipset_handle_t); +void ommmc_exec_command(sdmmc_chipset_handle_t, struct sdmmc_command *); +int ommmc_start_command(struct ommmc_softc *, struct sdmmc_command *); +int ommmc_wait_state(struct ommmc_softc *, uint32_t, uint32_t); +int ommmc_soft_reset(struct ommmc_softc *, int); +int ommmc_wait_intr(struct ommmc_softc *, int, int); +void ommmc_transfer_data(struct ommmc_softc *, struct sdmmc_command *); +void ommmc_read_data(struct ommmc_softc *, u_char *, int); +void ommmc_write_data(struct ommmc_softc *, u_char *, int); + +/* #define SDHC_DEBUG */ +#ifdef SDHC_DEBUG +int ommmcdebug = 20; +#define DPRINTF(n,s) do { if ((n) <= ommmcdebug) printf s; } while (0) +void ommmc_dump_regs(struct ommmc_softc *); +#else +#define DPRINTF(n,s) do {} while(0) +#endif + +struct sdmmc_chip_functions ommmc_functions = { + /* host controller reset */ + ommmc_host_reset, + /* host controller capabilities */ + ommmc_host_ocr, + ommmc_host_maxblklen, + /* card detection */ + ommmc_card_detect, + /* bus power and clock frequency */ + ommmc_bus_power, + ommmc_bus_clock, + /* command execution */ + ommmc_exec_command, + /* card interrupt */ + ommmc_card_intr_mask, + ommmc_card_intr_ack +}; + +struct cfdriver ommmc_cd = { + NULL, "ommmc", DV_DULL +}; + +struct cfattach ommmc_ca = { + sizeof(struct ommmc_softc), NULL, ommmc_attach +}; + +void +ommmc_attach(struct device *parent, struct device *self, void *args) +{ + struct ommmc_softc *sc = (struct ommmc_softc *) self; + struct omap_attach_args *oa = args; + struct sdmmcbus_attach_args saa; + int baseaddr; + int error = 1; + + /* XXX - ICLKEN, FCLKEN? */ + + baseaddr = oa->oa_dev->mem[0].addr; + if (board_id == BOARD_ID_OMAP4_PANDA || + board_id == BOARD_ID_AM335X_BEAGLEBONE) { + /* omap4430 has mmc registers offset +0x100 */ + baseaddr += 0x100; + } + + sc->sc_iot = oa->oa_iot; + if (bus_space_map(sc->sc_iot, baseaddr, oa->oa_dev->mem[0].size, + 0, &sc->sc_ioh)) + panic("%s: bus_space_map failed!", __func__); + + printf("\n"); + + /* XXX DMA channels? */ + /* FIXME prcm_enableclock(sc->clockbit); */ + + sc->sc_ih = arm_intr_establish(oa->oa_dev->irq[0], IPL_SDMMC, + ommmc_intr, sc, sc->sc_dev.dv_xname); + +#if 0 + /* XXX - IIRC firmware should set this */ + /* Controller Voltage Capabilities Initialization */ + HSET4(sc, MMCHS_CAPA, MMCHS_CAPA_VS18 | MMCHS_CAPA_VS30); +#endif + +#ifdef SDHC_DEBUG + ommmc_dump_regs(sc); +#endif + + /* + * Reset the host controller and enable interrupts. + */ + (void)ommmc_host_reset(sc); + +#if 0 + /* Determine host capabilities. */ + caps = HREAD4(sc, SDHC_CAPABILITIES); + + /* we want this !! */ + /* Use DMA if the host system and the controller support it. */ + if (usedma && ISSET(caps, SDHC_DMA_SUPPORT)) + SET(sc->flags, SHF_USE_DMA); +#endif + + /* + * Determine the base clock frequency. (2.2.24) + */ + + sc->clkbase = 96 * 1000; +#if 0 + if (SDHC_BASE_FREQ_KHZ(caps) != 0) + sc->clkbase = SDHC_BASE_FREQ_KHZ(caps); + sc->clkbase = SDHC_BASE_FREQ_KHZ(caps); +#endif + if (sc->clkbase == 0) { + /* The attachment driver must tell us. */ + printf("%s: base clock frequency unknown\n", + sc->sc_dev.dv_xname); + goto err; + } else if (sc->clkbase < 10000 || sc->clkbase > 96000) { + /* SDHC 1.0 supports only 10-63 MHz. */ + printf("%s: base clock frequency out of range: %u MHz\n", + sc->sc_dev.dv_xname, sc->clkbase / 1000); + goto err; + } + + /* + * XXX Set the data timeout counter value according to + * capabilities. (2.2.15) + */ + + + /* + * Determine SD bus voltage levels supported by the controller. + */ + if (HREAD4(sc, MMCHS_CAPA) & MMCHS_CAPA_VS18) + SET(sc->ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V); + if (HREAD4(sc, MMCHS_CAPA) & MMCHS_CAPA_VS30) + SET(sc->ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V); + if (HREAD4(sc, MMCHS_CAPA) & MMCHS_CAPA_VS33) + SET(sc->ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V); + + /* + * Omap max block size is fixed (single buffer), could limit + * this to 512 for double buffering, but dont see the point. + */ + switch ((HREAD4(sc, MMCHS_CAPA) & MMCHS_CAPA_MBL_MASK) + >> MMCHS_CAPA_MBL_SHIFT) { + case 0: + sc->maxblklen = 512; + break; + case 1: + sc->maxblklen = 1024; + break; + case 2: + sc->maxblklen = 2048; + break; + default: + sc->maxblklen = 512; + printf("invalid capability blocksize in capa %08x," + " trying 512\n", HREAD4(sc, MMCHS_CAPA)); + } + + sc->maxblklen = 512; /* XXX */ + + /* + * Attach the generic SD/MMC bus driver. (The bus driver must + * not invoke any chipset functions before it is attached.) + */ + bzero(&saa, sizeof(saa)); + saa.saa_busname = "sdmmc"; + saa.sct = &ommmc_functions; + saa.sch = sc; + + sc->sdmmc = config_found(&sc->sc_dev, &saa, NULL); + if (sc->sdmmc == NULL) { + error = 0; + goto err; + } + + return; + +err: + return; +} + + +/* + * Power hook established by or called from attachment driver. + */ +void +ommmc_power(int why, void *arg) +{ +#if 0 + struct ommmc_softc *sc = arg; + int n, i; +#endif + + switch(why) { + case DVACT_SUSPEND: + /* XXX poll for command completion or suspend command + * in progress */ + + /* Save the host controller state. */ +#if 0 + for (i = 0; i < sizeof sc->regs; i++) + sc->regs[i] = HREAD1(sc, i); +#endif + break; + + case DVACT_RESUME: + /* Restore the host controller state. */ +#if 0 + (void)ommmc_host_reset(sc); + for (i = 0; i < sizeof sc->regs; i++) + HWRITE1(sc, i, sc->regs[i]); +#endif + break; + } +} + +/* + * Shutdown hook established by or called from attachment driver. + */ +void +ommmc_shutdown(void *arg) +{ + struct ommmc_softc *sc = arg; + + /* XXX chip locks up if we don't disable it before reboot. */ + (void)ommmc_host_reset(sc); +} + +/* + * Reset the host controller. Called during initialization, when + * cards are removed, upon resume, and during error recovery. + */ +int +ommmc_host_reset(sdmmc_chipset_handle_t sch) +{ + struct ommmc_softc *sc = sch; + u_int32_t imask; + int error; + int s; + + s = splsdmmc(); + + /* Disable all interrupts. */ + HWRITE4(sc, MMCHS_IE, 0); + HWRITE4(sc, MMCHS_ISE, 0); + + /* + * Reset the entire host controller and wait up to 100ms for + * the controller to clear the reset bit. + */ + if ((error = ommmc_soft_reset(sc, MMCHS_SYSCTL_SRA)) != 0) { + splx(s); + return (error); + } + +#if 0 + HSET4(sc, MMCHS_CON, MMCHS_CON_INIT); + HWRITE4(sc, MMCHS_CMD, 0); + delay(100); /* should delay 1ms */ + + HWRITE4(sc, MMCHS_STAT, MMCHS_STAT_CC); + HCLR4(sc, MMCHS_CON, MMCHS_CON_INIT); + HWRITE4(sc, MMCHS_STAT, ~0); +#endif + + + /* Set data timeout counter value to max for now. */ + HSET4(sc, MMCHS_SYSCTL, 0xe << MMCHS_SYSCTL_DTO_SH); + + /* Enable interrupts. */ + imask = MMCHS_STAT_BRR | MMCHS_STAT_BWR | MMCHS_STAT_BGE | + MMCHS_STAT_TC | MMCHS_STAT_CC; + + imask |= MMCHS_STAT_BADA | MMCHS_STAT_CERR | MMCHS_STAT_DEB | + MMCHS_STAT_DCRC | MMCHS_STAT_DTO | MMCHS_STAT_CIE | + MMCHS_STAT_CEB | MMCHS_STAT_CCRC | MMCHS_STAT_CTO; + + HWRITE4(sc, MMCHS_IE, imask); + HWRITE4(sc, MMCHS_ISE, imask); + + splx(s); + return 0; +} + +uint32_t +ommmc_host_ocr(sdmmc_chipset_handle_t sch) +{ + struct ommmc_softc *sc = sch; + return sc->ocr; +} + +int +ommmc_host_maxblklen(sdmmc_chipset_handle_t sch) +{ + struct ommmc_softc *sc = sch; + return sc->maxblklen; +} + +/* + * Return non-zero if the card is currently inserted. + */ +int +ommmc_card_detect(sdmmc_chipset_handle_t sch) +{ +#if 0 + struct ommmc_softc *sc = sch; + return ISSET(HREAD4(sc, SDHC_PRESENT_STATE), SDHC_CARD_INSERTED) ? + 1 : 0; +#else + return 1; /* XXX */ +#endif +} + +/* + * Set or change SD bus voltage and enable or disable SD bus power. + * Return zero on success. + */ +int +ommmc_bus_power(sdmmc_chipset_handle_t sch, uint32_t ocr) +{ + struct ommmc_softc *sc = sch; + uint32_t vdd; + uint32_t reg; + int s; + + s = splsdmmc(); + + /* + * Disable bus power before voltage change. + */ + HCLR4(sc, MMCHS_HCTL, MMCHS_HCTL_SDBP); + + /* If power is disabled, reset the host and return now. */ + if (ocr == 0) { + splx(s); + (void)ommmc_host_reset(sc); + return 0; + } + + /* + * Select the maximum voltage according to capabilities. + */ + ocr &= sc->ocr; + + if (ISSET(ocr, MMC_OCR_3_2V_3_3V | MMC_OCR_3_3V_3_4V)) + vdd = MMCHS_HCTL_SDVS_V33; + else if (ISSET(ocr, MMC_OCR_2_9V_3_0V | MMC_OCR_3_0V_3_1V)) + vdd = MMCHS_HCTL_SDVS_V30; + else if (ISSET(ocr, MMC_OCR_1_7V_1_8V | MMC_OCR_1_8V_1_9V)) + vdd = MMCHS_HCTL_SDVS_V18; + else { + /* Unsupported voltage level requested. */ + splx(s); + return EINVAL; + } + + /* + * Enable bus power. Wait at least 1 ms (or 74 clocks) plus + * voltage ramp until power rises. + */ + reg = HREAD4(sc, MMCHS_HCTL); + reg &= MMCHS_HCTL_SDVS_MASK; + reg = vdd; + HWRITE4(sc, MMCHS_HCTL, reg); + + HSET4(sc, MMCHS_HCTL, MMCHS_HCTL_SDBP); + delay(10000); /* XXX */ + + /* + * The host system may not power the bus due to battery low, + * etc. In that case, the host controller should clear the + * bus power bit. + */ + if (!ISSET(HREAD4(sc, MMCHS_HCTL), MMCHS_HCTL_SDBP)) { + splx(s); + return ENXIO; + } + + splx(s); + return 0; +} + +/* + * Return the smallest possible base clock frequency divisor value + * for the CLOCK_CTL register to produce `freq' (KHz). + */ +static int +ommmc_clock_divisor(struct ommmc_softc *sc, u_int freq) +{ + int div; + uint32_t maxclk = MMCHS_SYSCTL_CLKD_MASK>>MMCHS_SYSCTL_CLKD_SH; + + for (div = 1; div <= maxclk; div++) + if ((sc->clkbase / div) <= freq) { + return (div); + } + + printf("divisor failure\n"); + /* No divisor found. */ + return -1; +} + +/* + * Set or change SDCLK frequency or disable the SD clock. + * Return zero on success. + */ +int +ommmc_bus_clock(sdmmc_chipset_handle_t sch, int freq) +{ + int error = 0; + struct ommmc_softc *sc = sch; + uint32_t reg; + int s; + int div; + int timo; + + s = splsdmmc(); + +#ifdef DIAGNOSTIC + /* Must not stop the clock if commands are in progress. */ + if (ISSET(HREAD4(sc, MMCHS_PSTATE), MMCHS_PSTATE_CMDI|MMCHS_PSTATE_DATI) + && ommmc_card_detect(sc)) + printf("ommmc_sdclk_frequency_select: command in progress\n"); +#endif + + /* + * Stop SD clock before changing the frequency. + */ + HCLR4(sc, MMCHS_SYSCTL, MMCHS_SYSCTL_CEN); + if (freq == SDMMC_SDCLK_OFF) + goto ret; + + /* + * Set the minimum base clock frequency divisor. + */ + if ((div = ommmc_clock_divisor(sc, freq)) < 0) { + /* Invalid base clock frequency or `freq' value. */ + error = EINVAL; + goto ret; + } + reg = HREAD4(sc, MMCHS_SYSCTL); + reg &= ~MMCHS_SYSCTL_CLKD_MASK; + reg |= div << MMCHS_SYSCTL_CLKD_SH; + HWRITE4(sc, MMCHS_SYSCTL, reg); + + /* + * Start internal clock. Wait 10ms for stabilization. + */ + HSET4(sc, MMCHS_SYSCTL, MMCHS_SYSCTL_ICE); + for (timo = 1000; timo > 0; timo--) { + if (ISSET(HREAD4(sc, MMCHS_SYSCTL), MMCHS_SYSCTL_ICS)) + break; + delay(10); + } + if (timo == 0) { + error = ETIMEDOUT; + goto ret; + } + + /* + * Enable SD clock. + */ + HSET4(sc, MMCHS_SYSCTL, MMCHS_SYSCTL_CEN); +ret: + splx(s); + return error; +} + +void +ommmc_card_intr_mask(sdmmc_chipset_handle_t sch, int enable) +{ + /* - this is SDIO card interrupt */ + struct ommmc_softc *sc = sch; + + if (enable) { + HSET4(sc, MMCHS_IE, MMCHS_STAT_CIRQ); + HSET4(sc, MMCHS_ISE, MMCHS_STAT_CIRQ); + } else { + HCLR4(sc, MMCHS_IE, MMCHS_STAT_CIRQ); + HCLR4(sc, MMCHS_ISE, MMCHS_STAT_CIRQ); + } +} + +void +ommmc_card_intr_ack(sdmmc_chipset_handle_t sch) +{ + struct ommmc_softc *sc = sch; + + HWRITE4(sc, MMCHS_STAT, MMCHS_STAT_CIRQ); +} + +int +ommmc_wait_state(struct ommmc_softc *sc, uint32_t mask, uint32_t value) +{ + uint32_t state; + int timeout; + + state = HREAD4(sc, MMCHS_PSTATE); + DPRINTF(3,("%s: wait_state %x %x %x(state=%b)\n", HDEVNAME(sc), + mask, value, state, state, MMCHS_PSTATE_FMT)); + for (timeout = 1000; timeout > 0; timeout--) { + if (((state = HREAD4(sc, MMCHS_PSTATE)) & mask) == value) + return 0; + delay(10); + } + DPRINTF(0,("%s: timeout waiting for %x (state=%b)\n", HDEVNAME(sc), + value, state, MMCHS_PSTATE_FMT)); + return ETIMEDOUT; +} + +void +ommmc_exec_command(sdmmc_chipset_handle_t sch, struct sdmmc_command *cmd) +{ + struct ommmc_softc *sc = sch; + int error; + + /* + * Start the MMC command, or mark `cmd' as failed and return. + */ + error = ommmc_start_command(sc, cmd); + if (error != 0) { + cmd->c_error = error; + SET(cmd->c_flags, SCF_ITSDONE); + return; + } + + /* + * Wait until the command phase is done, or until the command + * is marked done for any other reason. + */ + if (!ommmc_wait_intr(sc, MMCHS_STAT_CC, SDHC_COMMAND_TIMEOUT)) { + cmd->c_error = ETIMEDOUT; + SET(cmd->c_flags, SCF_ITSDONE); + return; + } + + /* + * The host controller removes bits [0:7] from the response + * data (CRC) and we pass the data up unchanged to the bus + * driver (without padding). + */ + if (cmd->c_error == 0 && ISSET(cmd->c_flags, SCF_RSP_PRESENT)) { + if (ISSET(cmd->c_flags, SCF_RSP_136)) { + uint32_t v0,v1,v2,v3; + v0 = HREAD4(sc, MMCHS_RSP10); + v1 = HREAD4(sc, MMCHS_RSP32); + v2 = HREAD4(sc, MMCHS_RSP54); + v3 = HREAD4(sc, MMCHS_RSP76); + + cmd->c_resp[0] = (v0 >> 8) | ((v1 & 0xff) << 24); + cmd->c_resp[1] = (v1 >> 8) | ((v2 & 0xff) << 24); + cmd->c_resp[2] = (v2 >> 8) | ((v3 & 0xff) << 24); + cmd->c_resp[3] = v3 >> 8; +#ifdef SDHC_DEBUG + printf("resp[0] 0x%08x\nresp[1] 0x%08x\nresp[2] 0x%08x\nresp[3] 0x%08x\n", cmd->c_resp[0], cmd->c_resp[1], cmd->c_resp[2], cmd->c_resp[3]); +#endif + } else { + cmd->c_resp[0] = HREAD4(sc, MMCHS_RSP10); +#ifdef SDHC_DEBUG + printf("resp[0] 0x%08x\n", cmd->c_resp[0]); +#endif + } + } + + /* + * If the command has data to transfer in any direction, + * execute the transfer now. + */ + if (cmd->c_error == 0 && cmd->c_data != NULL) + ommmc_transfer_data(sc, cmd); + +#if 0 + /* Turn off the LED. */ + HCLR1(sc, SDHC_HOST_CTL, SDHC_LED_ON); +#endif + + DPRINTF(1,("%s: cmd %u done (flags=%#x error=%d)\n", + HDEVNAME(sc), cmd->c_opcode, cmd->c_flags, cmd->c_error)); + SET(cmd->c_flags, SCF_ITSDONE); +} + +int +ommmc_start_command(struct ommmc_softc *sc, struct sdmmc_command *cmd) +{ + u_int32_t blksize = 0; + u_int32_t blkcount = 0; + u_int32_t command; + int error; + int s; + + DPRINTF(1,("%s: start cmd %u arg=%#x data=%#x dlen=%d flags=%#x " + "proc=\"%s\"\n", HDEVNAME(sc), cmd->c_opcode, cmd->c_arg, + cmd->c_data, cmd->c_datalen, cmd->c_flags, curproc ? + curproc->p_comm : "")); + + /* + * The maximum block length for commands should be the minimum + * of the host buffer size and the card buffer size. (1.7.2) + */ + + /* Fragment the data into proper blocks. */ + if (cmd->c_datalen > 0) { + blksize = MIN(cmd->c_datalen, cmd->c_blklen); + blkcount = cmd->c_datalen / blksize; + if (cmd->c_datalen % blksize > 0) { + /* XXX: Split this command. (1.7.4) */ + printf("%s: data not a multiple of %d bytes\n", + HDEVNAME(sc), blksize); + return EINVAL; + } + } + + /* Check limit imposed by 9-bit block count. (1.7.2) */ + if (blkcount > MMCHS_BLK_NBLK_MAX) { + printf("%s: too much data\n", HDEVNAME(sc)); + return EINVAL; + } + + /* Prepare transfer mode register value. (2.2.5) */ + command = 0; + if (ISSET(cmd->c_flags, SCF_CMD_READ)) + command |= MMCHS_CMD_DDIR; + if (blkcount > 0) { + command |= MMCHS_CMD_BCE; + if (blkcount > 1) { + command |= MMCHS_CMD_MSBS; + /* XXX only for memory commands? */ + command |= MMCHS_CMD_ACEN; + } + } +#ifdef notyet + if (ISSET(sc->flags, SHF_USE_DMA)) + command |= MMCHS_CMD_DE; +#endif + + /* + * Prepare command register value. (2.2.6) + */ + command |= (cmd->c_opcode << MMCHS_CMD_INDX_SHIFT) & + MMCHS_CMD_INDX_SHIFT_MASK; + + if (ISSET(cmd->c_flags, SCF_RSP_CRC)) + command |= MMCHS_CMD_CCCE; + if (ISSET(cmd->c_flags, SCF_RSP_IDX)) + command |= MMCHS_CMD_CICE; + if (cmd->c_data != NULL) + command |= MMCHS_CMD_DP; + + if (!ISSET(cmd->c_flags, SCF_RSP_PRESENT)) + command |= MMCHS_CMD_RESP_NONE; + else if (ISSET(cmd->c_flags, SCF_RSP_136)) + command |= MMCHS_CMD_RESP136; + else if (ISSET(cmd->c_flags, SCF_RSP_BSY)) + command |= MMCHS_CMD_RESP48B; + else + command |= MMCHS_CMD_RESP48; + + /* Wait until command and data inhibit bits are clear. (1.5) */ + if ((error = ommmc_wait_state(sc, MMCHS_PSTATE_CMDI, 0)) != 0) + return error; + + s = splsdmmc(); + +#if 0 + /* Alert the user not to remove the card. */ + HSET1(sc, SDHC_HOST_CTL, SDHC_LED_ON); +#endif + + /* XXX: Set DMA start address if SHF_USE_DMA is set. */ + + DPRINTF(1,("%s: cmd=%#x blksize=%d blkcount=%d\n", + HDEVNAME(sc), command, blksize, blkcount)); + + /* + * Start a CPU data transfer. Writing to the high order byte + * of the SDHC_COMMAND register triggers the SD command. (1.5) + */ + HWRITE4(sc, MMCHS_BLK, (blkcount << MMCHS_BLK_NBLK_SHIFT) | + (blksize << MMCHS_BLK_BLEN_SHIFT)); + HWRITE4(sc, MMCHS_ARG, cmd->c_arg); + HWRITE4(sc, MMCHS_CMD, command); + + splx(s); + return 0; +} + +void +ommmc_transfer_data(struct ommmc_softc *sc, struct sdmmc_command *cmd) +{ + u_char *datap = cmd->c_data; + int i, datalen; + int mask; + int error; + + mask = ISSET(cmd->c_flags, SCF_CMD_READ) ? + MMCHS_PSTATE_BRE : MMCHS_PSTATE_BWE; + error = 0; + datalen = cmd->c_datalen; + + DPRINTF(1,("%s: resp=%#x datalen=%d\n", HDEVNAME(sc), + MMC_R1(cmd->c_resp), datalen)); + + while (datalen > 0) { + if (!ommmc_wait_intr(sc, MMCHS_STAT_BRR| MMCHS_STAT_BWR, + SDHC_BUFFER_TIMEOUT)) { + error = ETIMEDOUT; + break; + } + + if ((error = ommmc_wait_state(sc, mask, mask)) != 0) + break; + + i = MIN(datalen, cmd->c_blklen); + if (ISSET(cmd->c_flags, SCF_CMD_READ)) + ommmc_read_data(sc, datap, i); + else + ommmc_write_data(sc, datap, i); + + datap += i; + datalen -= i; + } + + if (error == 0 && !ommmc_wait_intr(sc, MMCHS_STAT_TC, + SDHC_TRANSFER_TIMEOUT)) + error = ETIMEDOUT; + + if (error != 0) + cmd->c_error = error; + SET(cmd->c_flags, SCF_ITSDONE); + + DPRINTF(1,("%s: data transfer done (error=%d)\n", + HDEVNAME(sc), cmd->c_error)); +} + +void +ommmc_read_data(struct ommmc_softc *sc, u_char *datap, int datalen) +{ + while (datalen > 3) { + *(uint32_t *)datap = HREAD4(sc, MMCHS_DATA); + datap += 4; + datalen -= 4; + } + if (datalen > 0) { + uint32_t rv = HREAD4(sc, MMCHS_DATA); + do { + *datap++ = rv & 0xff; + rv = rv >> 8; + } while (--datalen > 0); + } +} + +void +ommmc_write_data(struct ommmc_softc *sc, u_char *datap, int datalen) +{ + while (datalen > 3) { + DPRINTF(3,("%08x\n", *(uint32_t *)datap)); + HWRITE4(sc, MMCHS_DATA, *((uint32_t *)datap)); + datap += 4; + datalen -= 4; + } + if (datalen > 0) { + uint32_t rv = *datap++; + if (datalen > 1) + rv |= *datap++ << 8; + if (datalen > 2) + rv |= *datap++ << 16; + DPRINTF(3,("rv %08x\n", rv)); + HWRITE4(sc, MMCHS_DATA, rv); + } +} + +/* Prepare for another command. */ +int +ommmc_soft_reset(struct ommmc_softc *sc, int mask) +{ + + int timo; + + DPRINTF(1,("%s: software reset reg=%#x\n", HDEVNAME(sc), mask)); + + HSET4(sc, MMCHS_SYSCTL, mask); + delay(10); + for (timo = 1000; timo > 0; timo--) { + if (!ISSET(HREAD4(sc, MMCHS_SYSCTL), mask)) + break; + delay(10); + } + if (timo == 0) { + DPRINTF(1,("%s: timeout reg=%#x\n", HDEVNAME(sc), + HREAD4(sc, MMCHS_SYSCTL))); + return (ETIMEDOUT); + } + + return (0); +} + +int +ommmc_wait_intr(struct ommmc_softc *sc, int mask, int timo) +{ + int status; + int s; + + mask |= MMCHS_STAT_ERRI; + + s = splsdmmc(); + status = sc->intr_status & mask; + while (status == 0) { + if (tsleep(&sc->intr_status, PWAIT, "hcintr", timo) + == EWOULDBLOCK) { + status |= MMCHS_STAT_ERRI; + break; + } + status = sc->intr_status & mask; + } + sc->intr_status &= ~status; + + DPRINTF(2,("%s: intr status %#x error %#x\n", HDEVNAME(sc), status, + sc->intr_error_status)); + + /* Command timeout has higher priority than command complete. */ + if (ISSET(status, MMCHS_STAT_ERRI)) { + sc->intr_error_status = 0; + (void)ommmc_soft_reset(sc, MMCHS_SYSCTL_SRC|MMCHS_SYSCTL_SRD); + status = 0; + } + + splx(s); + return status; +} + +/* + * Established by attachment driver at interrupt priority IPL_SDMMC. + */ +int +ommmc_intr(void *arg) +{ + struct ommmc_softc *sc = arg; + + u_int32_t status; + + /* Find out which interrupts are pending. */ + status = HREAD4(sc, MMCHS_STAT); + + /* Acknowledge the interrupts we are about to handle. */ + HWRITE4(sc, MMCHS_STAT, status); + DPRINTF(2,("%s: interrupt status=%b\n", HDEVNAME(sc), + status, MMCHS_STAT_FMT)); + + /* + * Service error interrupts. + */ + if (ISSET(status, MMCHS_STAT_ERRI)) { + if (ISSET(status, MMCHS_STAT_CTO| + MMCHS_STAT_DTO)) { + sc->intr_status |= status; + sc->intr_error_status |= status & 0xffff0000; + wakeup(&sc->intr_status); + } + } + +#if 0 + /* + * Wake up the sdmmc event thread to scan for cards. + */ + if (ISSET(status, SDHC_CARD_REMOVAL|SDHC_CARD_INSERTION)) + ommmc_needs_discover(sc->sdmmc); +#endif + + /* + * Wake up the blocking process to service command + * related interrupt(s). + */ + if (ISSET(status, MMCHS_STAT_BRR| + MMCHS_STAT_BWR|MMCHS_STAT_TC| + MMCHS_STAT_CC)) { + sc->intr_status |= status; + wakeup(&sc->intr_status); + } + + /* + * Service SD card interrupts. + */ + if (ISSET(status, MMCHS_STAT_CIRQ)) { + DPRINTF(0,("%s: card interrupt\n", HDEVNAME(sc))); + HCLR4(sc, MMCHS_STAT, MMCHS_STAT_CIRQ); + sdmmc_card_intr(sc->sdmmc); + } + return 1; +} + +#ifdef SDHC_DEBUG + +struct { + char * name; + uint32_t off; + } reglist[] = { + { "MMCHS_SYSCONFIG", 0x010 }, + { "MMCHS_SYSSTATUS", 0x014 }, + { "MMCHS_CSRE", 0x024 }, + { "MMCHS_SYSTEST", 0x028 }, + { "MMCHS_CON", 0x02C }, + { "MMCHS_PWCNT", 0x030 }, + { "MMCHS_BLK", 0x104 }, + { "MMCHS_ARG", 0x108 }, + { "MMCHS_CMD", 0x10C }, + { "MMCHS_RSP10", 0x110 }, + { "MMCHS_RSP32", 0x114 }, + { "MMCHS_RSP54", 0x118 }, + { "MMCHS_RSP76", 0x11C }, + { "MMCHS_DATA", 0x120 }, + { "MMCHS_PSTATE", 0x124 }, + { "MMCHS_HCTL", 0x128 }, + { "MMCHS_SYSCTL", 0x12C }, + { "MMCHS_STAT", 0x130 }, + { "MMCHS_IE", 0x134 }, + { "MMCHS_ISE", 0x138 }, + { "MMCHS_AC12", 0x13C }, + { "MMCHS_CAPA", 0x140 }, + { "MMCHS_CUR_CAPA", 0x148 }, + { NULL, 0x0 } +}; +void +ommmc_dump_regs(struct ommmc_softc *sc) +{ + int i; + for (i = 0; reglist[i].name != NULL; i++) { + printf("reg %s = %08x\n", reglist[i].name, + HREAD4(sc, reglist[i].off)); + } +} +#endif diff --git a/sys/arch/armv7/omap/omohci.c b/sys/arch/armv7/omap/omohci.c new file mode 100644 index 00000000000..976a35bbef1 --- /dev/null +++ b/sys/arch/armv7/omap/omohci.c @@ -0,0 +1,353 @@ +/* $OpenBSD: omohci.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ + +/* + * Copyright (c) 2005 David Gwynne <dlg@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/device.h> +#include <sys/kernel.h> +#include <sys/timeout.h> + +#include <machine/intr.h> +#include <machine/bus.h> + +#include <dev/usb/usb.h> +#include <dev/usb/usbdi.h> +#include <dev/usb/usbdivar.h> +#include <dev/usb/usb_mem.h> + +#include <dev/usb/ohcireg.h> +#include <dev/usb/ohcivar.h> +#include <armv7/omap/omapvar.h> +#include <armv7/omap/prcmvar.h> + +#define HOSTUEADDR 0x0E0 +#define HOSTUESTATUS 0x0E4 +#define HOSTTIMEOUTCTRL 0x0E8 +#define HOSTREVISION 0x0EC +#define WHM_REVID_REGISTER 0x0F4 +#define WHM_TEST_OBSV 0x0F8 +#define WHM_TEST_CTL 0x0FC +#define HHC_TEST_CFG 0x100 +#define HHC_TEST_CTL 0x104 +#define HHC_TEST_OBSV 0x108 +#define REVDEV 0x200 /* 16 bit */ +#define EP_NUM 0x204 /* 16 bit */ +#define DATA 0x208 /* 16 bit */ +#define CTRL 0x20C /* 16 bit */ +#define STAT_FLG 0x210 /* 16 bit */ +#define RXFSTAT 0x214 /* 16 bit */ +#define SYSCON1 0x218 /* 16 bit */ +#define SYSCON2 0x21C /* 16 bit */ +#define DEVSTAT 0x220 /* 16 bit */ +#define SOFREG 0x224 /* 16 bit */ +#define IRQ_EN 0x228 /* 16 bit */ +#define DMA_IRQ_EN 0x22C /* 16 bit */ +#define IRQ_SRC 0x230 /* 16 bit */ +#define EPN_STAT 0x234 /* 16 bit */ +#define DMAN_STAT 0x238 /* 16 bit */ +#define RXDMA_CFG 0x240 /* 16 bit */ +#define TXDMA_CFG 0x244 /* 16 bit */ + +#define TXDMA0 0x250 +#define TXDMA1 0x254 +#define TXDMA2 0x258 +#define RXDMA0 0x260 +#define RXDMA1 0x264 +#define RXDMA2 0x268 + +#define EP0 0x280 +#define EP_RX(x) 0x280 + (x * 4) +#define EP_TX(x) 0x2C0 + (x * 4) + +#define OTG_REV 0x300 +#define OTG_SYSCON_1 0x304 +#define OTG_SYSCON_2 0x308 +#define OTG_SYSCON2_OTG_EN 0x80000000 +#define OTG_SYSCON2_UHOST_EN 0x00000100 +#define OTG_SYSCON2_MODE_DISABLED 0x00000000 +#define OTG_SYSCON2_MODE_CLIENT 0x00000001 +#define OTG_SYSCON2_MODE_HOST 0x00000004 +#define OTG_CTRL 0x30C +#if 0 +#define OTG_IRQ_EN 0x310 /* 16 bit */ +#define OTG_IRQ_SRC 0x314 /* 16 bit */ +#define OTG_OUTCTRL 0x318 /* 16 bit */ +#define OTG_TEST 0x320 /* 16 bit */ +#endif +#define OTG_VC 0x3FC + + +int omohci_match(struct device *, void *, void *); +void omohci_attach(struct device *, struct device *, void *); +int omohci_detach(struct device *, int); +int omohci_activate(struct device *, int); + +struct omohci_softc { + struct ohci_softc sc; + void *sc_ihc0; + void *sc_ihc1; + void *sc_ihc2; + void *sc_ih0; + void *sc_ih1; + void *sc_ihotg; +}; + +void omohci_enable(struct omohci_softc *); +void omohci_disable(struct omohci_softc *); + +struct cfattach omohci_ca = { + sizeof (struct omohci_softc), omohci_match, omohci_attach, + omohci_detach, omohci_detach +}; + +int +omohci_match(struct device *parent, void *match, void *aux) +{ +#if 0 + if ((cputype & ~CPU_ID_XSCALE_COREREV_MASK) != CPU_ID_PXA27X) + return (0); +#endif + + return (1); +} + +void +omohci_attach(struct device *parent, struct device *self, void *aux) +{ + struct omohci_softc *sc = (struct omohci_softc *)self; + struct ahb_attach_args *aa = aux; + usbd_status r; + + sc->sc.iot = aa->aa_iot; + sc->sc.sc_bus.dmatag = aa->aa_dmat; + sc->sc_ih0 = NULL; + sc->sc_ih1 = NULL; + sc->sc_ihc0 = NULL; + sc->sc_ihc1 = NULL; + sc->sc_ihc2 = NULL; + sc->sc_ihotg = NULL; + sc->sc.sc_size = 0; + + /* Map I/O space */ + if (bus_space_map(sc->sc.iot, aa->aa_addr, aa->aa_size, 0, + &sc->sc.ioh)) { + printf(": cannot map mem space\n"); + return; + } + sc->sc.sc_size = aa->aa_size; + + /* XXX copied from ohci_pci.c. needed? */ + bus_space_barrier(sc->sc.iot, sc->sc.ioh, 0, sc->sc.sc_size, + BUS_SPACE_BARRIER_READ|BUS_SPACE_BARRIER_WRITE); + +#if 0 + /* start the usb clock */ + pxa2x0_clkman_config(CKEN_USBHC, 1); +#endif + omohci_enable(sc); + + /* Disable interrupts, so we don't get any spurious ones. */ + bus_space_write_4(sc->sc.iot, sc->sc.ioh, OHCI_INTERRUPT_DISABLE, + OHCI_MIE); + + sc->sc_ihc0 = arm_intr_establish(aa->aa_intr, IPL_USB, + ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); + sc->sc_ihc1 = arm_intr_establish(aa->aa_intr+1, IPL_USB, + ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); + sc->sc_ihc2 = arm_intr_establish(aa->aa_intr+2, IPL_USB, + ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); + sc->sc_ih0 = arm_intr_establish(aa->aa_intr+3, IPL_USB, + ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); + sc->sc_ih1 = arm_intr_establish(aa->aa_intr+4, IPL_USB, + ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); + sc->sc_ihotg = arm_intr_establish(aa->aa_intr+5, IPL_USB, + ohci_intr, &sc->sc, sc->sc.sc_bus.bdev.dv_xname); + if (sc->sc_ih0 == NULL || + sc->sc_ih1 == NULL || + sc->sc_ihc0 == NULL || + sc->sc_ihc1 == NULL || + sc->sc_ihc2 == NULL || + sc->sc_ihotg == NULL) { + printf(": unable to establish interrupt\n"); + omohci_disable(sc); +#if 0 + pxa2x0_clkman_config(CKEN_USBHC, 0); +#endif + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); + sc->sc.sc_size = 0; + return; + } + + prcm_enablemodule(PRCM_USB); + + bus_space_write_4(sc->sc.iot, sc->sc.ioh, OTG_SYSCON_2, + OTG_SYSCON2_UHOST_EN | OTG_SYSCON2_MODE_HOST); + + strlcpy(sc->sc.sc_vendor, "OMAP24xx", sizeof(sc->sc.sc_vendor)); + r = ohci_init(&sc->sc); + if (r != USBD_NORMAL_COMPLETION) { + printf("%s: init failed, error=%d\n", + sc->sc.sc_bus.bdev.dv_xname, r); + arm_intr_disestablish(sc->sc_ih0); + arm_intr_disestablish(sc->sc_ih1); + arm_intr_disestablish(sc->sc_ihc0); + arm_intr_disestablish(sc->sc_ihc1); + arm_intr_disestablish(sc->sc_ihc2); + arm_intr_disestablish(sc->sc_ihotg); + sc->sc_ih0 = NULL; + sc->sc_ih1 = NULL; + sc->sc_ihc0 = NULL; + sc->sc_ihc1 = NULL; + sc->sc_ihc2 = NULL; + sc->sc_ihotg = NULL; + omohci_disable(sc); +#if 0 + pxa2x0_clkman_config(CKEN_USBHC, 0); +#endif + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); + sc->sc.sc_size = 0; + return; + } + + sc->sc.sc_child = config_found((void *)sc, &sc->sc.sc_bus, + usbctlprint); +} + +int +omohci_detach(struct device *self, int flags) +{ + struct omohci_softc *sc = (struct omohci_softc *)self; + int rv; + + rv = ohci_detach(&sc->sc, flags); + if (rv) + return (rv); + + if (sc->sc_ih0 != NULL) { + arm_intr_disestablish(sc->sc_ih0); + arm_intr_disestablish(sc->sc_ih1); + arm_intr_disestablish(sc->sc_ihc0); + arm_intr_disestablish(sc->sc_ihc1); + arm_intr_disestablish(sc->sc_ihc2); + arm_intr_disestablish(sc->sc_ihotg); + sc->sc_ih0 = NULL; + sc->sc_ih1 = NULL; + sc->sc_ihc0 = NULL; + sc->sc_ihc1 = NULL; + sc->sc_ihc2 = NULL; + sc->sc_ihotg = NULL; + } + + omohci_disable(sc); + + /* stop clock */ +#if 0 + pxa2x0_clkman_config(CKEN_USBHC, 0); +#endif + + if (sc->sc.sc_size) { + bus_space_unmap(sc->sc.iot, sc->sc.ioh, sc->sc.sc_size); + sc->sc.sc_size = 0; + } + + return (0); +} + + +int +omohci_activate(struct device *self, int act) +{ + struct omohci_softc *sc = (struct omohci_softc *)self; + + switch (act) { + case DVACT_SUSPEND: + sc->sc.sc_bus.use_polling++; + ohci_power(why, &sc->sc); +#if 0 + pxa2x0_clkman_config(CKEN_USBHC, 0); +#endif + sc->sc.sc_bus.use_polling--; + break; + + case DVACT_RESUME: + sc->sc.sc_bus.use_polling++; +#if 0 + pxa2x0_clkman_config(CKEN_USBHC, 1); +#endif + omohci_enable(sc); + ohci_power(why, &sc->sc); + sc->sc.sc_bus.use_polling--; + break; + } + return 0; +} + +void +omohci_enable(struct omohci_softc *sc) +{ +#if 0 + u_int32_t hr; + + /* Full host reset */ + hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, + (hr & USBHC_HR_MASK) | USBHC_HR_FHR); + + DELAY(USBHC_RST_WAIT); + + hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, + (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); + + /* Force system bus interface reset */ + hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, + (hr & USBHC_HR_MASK) | USBHC_HR_FSBIR); + + while (bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR) & \ + USBHC_HR_FSBIR) + DELAY(3); + + /* Enable the ports (physically only one, only enable that one?) */ + hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, + (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSE)); + hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, + (hr & USBHC_HR_MASK) & ~(USBHC_HR_SSEP2)); +#endif +} + +void +omohci_disable(struct omohci_softc *sc) +{ +#if 0 + u_int32_t hr; + + /* Full host reset */ + hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, + (hr & USBHC_HR_MASK) | USBHC_HR_FHR); + + DELAY(USBHC_RST_WAIT); + + hr = bus_space_read_4(sc->sc.iot, sc->sc.ioh, USBHC_HR); + bus_space_write_4(sc->sc.iot, sc->sc.ioh, USBHC_HR, + (hr & USBHC_HR_MASK) & ~(USBHC_HR_FHR)); +#endif +} diff --git a/sys/arch/armv7/omap/omusbtll.c b/sys/arch/armv7/omap/omusbtll.c new file mode 100644 index 00000000000..ba2daa7a75c --- /dev/null +++ b/sys/arch/armv7/omap/omusbtll.c @@ -0,0 +1,175 @@ +/* $OpenBSD: omusbtll.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ +/* + * Copyright (c) 2010 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/queue.h> +#include <sys/device.h> +#include <sys/malloc.h> +#include <sys/evcount.h> +#include <machine/bus.h> +#include <machine/intr.h> +#include <armv7/omap/omapvar.h> +#include <armv7/omap/prcmvar.h> + +/* registers */ +#define USBTLL_REVISION 0x0000 +#define USBTLL_SYSCONFIG 0x0010 +#define USBTLL_SYSSTATUS 0x0014 +#define USBTLL_IRQSTATUS 0x0018 +#define USBTLL_IRQENABLE 0x001C +#define USBTLL_SHARED_CONF 0x0030 +#define USBTLL_SHARED_CONF_USB_90D_DDR_EN (1<<6) +#define USBTLL_SHARED_CONF_USB_180D_SDR_EN (1<<5) +#define USBTLL_SHARED_CONF_USB_DIVRATIO_SH 2 +#define USBTLL_SHARED_CONF_FCLK_REQ (1<<1) +#define USBTLL_SHARED_CONF_FCLK_IS_ON (1<<0) + +#define USBTLL_CHANNEL_CONF_(i) (0x0040 + (0x04 * (i))) +#define USBTLL_CHANNEL_CONF_FSLSLINESTATE_SH 28 +#define USBTLL_CHANNEL_CONF_FSLSMODE_SH 24 +#define USBTLL_CHANNEL_CONF_TESTTXSE0 (1<<20) +#define USBTLL_CHANNEL_CONF_TESTTXDAT (1<<19) +#define USBTLL_CHANNEL_CONF_TESTTXEN (1<<18) +#define USBTLL_CHANNEL_CONF_TESTEN (1<<17) +#define USBTLL_CHANNEL_CONF_DRVVBUS (1<<16) +#define USBTLL_CHANNEL_CONF_CHRGVBUS (1<<15) +#define USBTLL_CHANNEL_CONF_ULPINOBITSTUFF (1<<11) +#define USBTLL_CHANNEL_CONF_ULPIAUTOIDLE (1<<10) +#define USBTLL_CHANNEL_CONF_UTMIAUTOIDLE (1<<9) +#define USBTLL_CHANNEL_CONF_ULPIDDRMODE (1<<8) +#define USBTLL_CHANNEL_CONF_LPIOUTCLKMODE (1<<7) +#define USBTLL_CHANNEL_CONF_TLLFULLSPEED (1<<6) +#define USBTLL_CHANNEL_CONF_TLLCONNECT (1<<5) +#define USBTLL_CHANNEL_CONF_TLLATTACH (1<<4) +#define USBTLL_CHANNEL_CONF_UTMIISADEV (1<<3) +#define USBTLL_CHANNEL_CONF_CHANMODE_SH 1 +#define USBTLL_CHANNEL_CONF_CHANEN (1<<0) + +/* +ULPI_VENDOR_ID_LO_(i) (0x0800 + (0x100 * (i))) +ULPI_VENDOR_ID_HI_(i) (0x0801 + (0x100 * (i))) +ULPI_PRODUCT_ID_LO_(i) (0x0802 + (0x100 * (i))) +ULPI_PRODUCT_ID_HI_(i) (0x0803 + (0x100 * (i))) +ULPI_FUNCTION_CTRL_(i) (0x0804 + (0x100 * (i))) +ULPI_FUNCTION_CTRL_SET_(i) (0x0805 + (0x100 * (i))) +ULPI_FUNCTION_CTRL_CLR_(i) (0x0806 + (0x100 * (i))) +ULPI_INTERFACE_CTRL_(i) (0x0807 + (0x100 * (i))) +ULPI_INTERFACE_CTRL_SET_(i) (0x0808 + (0x100 * (i))) +ULPI_INTERFACE_CTRL_CLR_(i) (0x0809 + (0x100 * (i))) +ULPI_OTG_CTRL_(i) (0x080A + (0x100 * (i))) +ULPI_OTG_CTRL_SET_(i) (0x080B + (0x100 * (i))) +ULPI_OTG_CTRL_CLR_(i) (0x080C + (0x100 * (i))) +ULPI_USB_INT_EN_RISE_(i) (0x080D + (0x100 * (i))) +ULPI_USB_INT_EN_RISE_SET_(i) (0x080E + (0x100 * (i))) +ULPI_USB_INT_EN_RISE_CLR_(i) (0x080F + (0x100 * (i))) +ULPI_USB_INT_EN_FALL_(i) (0x0810 + (0x100 * (i))) +ULPI_USB_INT_EN_FALL_SET_(i) (0x0811 + (0x100 * (i))) +ULPI_USB_INT_EN_FALL_CLR_(i) (0x0812 + (0x100 * (i))) +ULPI_USB_INT_STATUS_(i) (0x0813 + (0x100 * (i))) +ULPI_USB_INT_LATCH_(i) (0x0814 + (0x100 * (i))) +*/ + +struct omusbtll_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +void omusbtll_attach(struct device *parent, struct device *self, void *args); +void omusbtll_init(uint32_t channel_mask); + +struct cfattach omusbtll_ca = { + sizeof (struct omusbtll_softc), NULL, omusbtll_attach +}; + +struct cfdriver omusbtll_cd = { + NULL, "omusbtll", DV_DULL +}; + +struct omusbtll_softc *omusbtll_sc; +void +omusbtll_attach(struct device *parent, struct device *self, void *args) +{ + struct omusbtll_softc *sc = (struct omusbtll_softc *) self; + struct omap_attach_args *oa = args; + u_int32_t rev; + + sc->sc_iot = oa->oa_iot; + if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &sc->sc_ioh)) { + printf("%s: bus_space_map failed!\n", __func__); + return; + } + +#if 0 + prcm_enablemodule(PRCM_USBHOST1); + prcm_enablemodule(PRCM_USBHOST2); +#endif + prcm_enablemodule(PRCM_USBTLL); + + delay(10000); + + //return; +#if 1 + rev = bus_space_read_1(sc->sc_iot, sc->sc_ioh, USBTLL_SYSCONFIG); + + printf(" rev %d.%d\n", rev >> 4 & 0xf, rev & 0xf); +#endif + + omusbtll_sc = sc; + + omusbtll_init(0x3); +} + + +void omusbtll_init(uint32_t channel_mask) +{ + int i; + uint32_t val; + /* global reacharound */ + struct omusbtll_softc *sc = omusbtll_sc; + + for(i = 0; i < 3; i++) { + val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + USBTLL_CHANNEL_CONF_(i)); + val &= ~(USBTLL_CHANNEL_CONF_ULPINOBITSTUFF | + USBTLL_CHANNEL_CONF_ULPIAUTOIDLE | + USBTLL_CHANNEL_CONF_ULPIDDRMODE); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + USBTLL_CHANNEL_CONF_(i), val); + } + + val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, USBTLL_SHARED_CONF); + val |= (USBTLL_SHARED_CONF_USB_180D_SDR_EN | + (1 << USBTLL_SHARED_CONF_USB_DIVRATIO_SH) | + USBTLL_SHARED_CONF_FCLK_IS_ON); + val &= ~(USBTLL_SHARED_CONF_USB_90D_DDR_EN); + bus_space_write_4(sc->sc_iot, sc->sc_ioh, USBTLL_SHARED_CONF, val); + + for (i = 0; i < 3; i++) { + if (channel_mask & (1<<i)) { + val = bus_space_read_4(sc->sc_iot, sc->sc_ioh, + USBTLL_CHANNEL_CONF_(i)); + + val |= USBTLL_CHANNEL_CONF_CHANEN; + bus_space_write_4(sc->sc_iot, sc->sc_ioh, + USBTLL_CHANNEL_CONF_(i), val); + printf("usbtll enabling %d\n", i); + } + } +} diff --git a/sys/arch/armv7/omap/prcm.c b/sys/arch/armv7/omap/prcm.c new file mode 100644 index 00000000000..c255c861962 --- /dev/null +++ b/sys/arch/armv7/omap/prcm.c @@ -0,0 +1,482 @@ +/* $OpenBSD: prcm.c,v 1.1 2013/09/04 14:38:31 patrick Exp $ */ +/* + * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +/*- + * Copyright (c) 2011 + * Ben Gray <ben.r.gray@gmail.com>. + * All rights reserved. + * + * 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. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/* + * Driver for the Power, Reset and Clock Management Module (PRCM). + */ + +#include <sys/types.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/time.h> +#include <sys/device.h> + +#include <machine/bus.h> +#include <machine/intr.h> +#include <arm/cpufunc.h> +#include <armv7/omap/omapvar.h> +#include <armv7/omap/prcmvar.h> + +#include <armv7/omap/am335x_prcmreg.h> +#include <armv7/omap/omap3_prcmreg.h> +#include <armv7/omap/omap4_prcmreg.h> + +#define PRCM_REVISION 0x0800 +#define PRCM_SYSCONFIG 0x0810 + +uint32_t prcm_imask_mask[PRCM_REG_MAX]; +uint32_t prcm_fmask_mask[PRCM_REG_MAX]; +uint32_t prcm_imask_addr[PRCM_REG_MAX]; +uint32_t prcm_fmask_addr[PRCM_REG_MAX]; + +#define SYS_CLK 13 /* SYS_CLK speed in MHz */ + +struct prcm_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_prcm; + bus_space_handle_t sc_cm1; + bus_space_handle_t sc_cm2; + void (*sc_setup)(struct prcm_softc *sc); + void (*sc_enablemodule)(struct prcm_softc *sc, int mod); + void (*sc_setclock)(struct prcm_softc *sc, + int clock, int speed); + uint32_t cm1_avail; + uint32_t cm2_avail; +}; + +int prcm_match(struct device *, void *, void *); +void prcm_attach(struct device *, struct device *, void *); +int prcm_setup_dpll5(struct prcm_softc *); +uint32_t prcm_v3_bit(int mod); +uint32_t prcm_am335x_clkctrl(int mod); + +void prcm_am335x_enablemodule(struct prcm_softc *, int); +void prcm_am335x_setclock(struct prcm_softc *, int, int); + +void prcm_v3_setup(struct prcm_softc *); +void prcm_v3_enablemodule(struct prcm_softc *, int); +void prcm_v3_setclock(struct prcm_softc *, int, int); + +void prcm_v4_enablemodule(struct prcm_softc *, int); +int prcm_v4_hsusbhost_activate(int); +int prcm_v4_hsusbhost_set_source(int, int); + +struct cfattach prcm_ca = { + sizeof (struct prcm_softc), NULL, prcm_attach +}; + +struct cfdriver prcm_cd = { + NULL, "prcm", DV_DULL +}; + +void +prcm_attach(struct device *parent, struct device *self, void *args) +{ + struct omap_attach_args *oa = args; + struct prcm_softc *sc = (struct prcm_softc *) self; + u_int32_t reg; + + sc->sc_iot = oa->oa_iot; + + switch (board_id) { + case BOARD_ID_AM335X_BEAGLEBONE: + sc->sc_setup = NULL; + sc->sc_enablemodule = prcm_am335x_enablemodule; + sc->sc_setclock = prcm_am335x_setclock; + break; + case BOARD_ID_OMAP3_BEAGLE: + case BOARD_ID_OMAP3_OVERO: + sc->sc_setup = prcm_v3_setup; + sc->sc_enablemodule = prcm_v3_enablemodule; + sc->sc_setclock = prcm_v3_setclock; + break; + case BOARD_ID_OMAP4_PANDA: + sc->sc_setup = NULL; + sc->sc_enablemodule = prcm_v4_enablemodule; + sc->sc_setclock = NULL; + sc->cm1_avail = 1; + sc->cm2_avail = 1; + break; + } + + if (bus_space_map(sc->sc_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &sc->sc_prcm)) + panic("prcm_attach: bus_space_map failed!"); + + if (sc->cm1_avail && + bus_space_map(sc->sc_iot, oa->oa_dev->mem[1].addr, + oa->oa_dev->mem[1].size, 0, &sc->sc_cm1)) + panic("prcm_attach: bus_space_map failed!"); + + if (sc->cm2_avail && + bus_space_map(sc->sc_iot, oa->oa_dev->mem[2].addr, + oa->oa_dev->mem[2].size, 0, &sc->sc_cm2)) + panic("prcm_attach: bus_space_map failed!"); + + reg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, PRCM_REVISION); + printf(" rev %d.%d\n", reg >> 4 & 0xf, reg & 0xf); + + if (sc->sc_setup) + sc->sc_setup(sc); + + printf("\n"); +} + +void +prcm_v3_setup(struct prcm_softc *sc) +{ + /* Setup the 120MHZ DPLL5 clock, to be used by USB. */ + prcm_setup_dpll5(sc); + + prcm_fmask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FMASK; + prcm_imask_mask[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IMASK; + prcm_fmask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_FADDR; + prcm_imask_addr[PRCM_REG_CORE_CLK1] = PRCM_REG_CORE_CLK1_IADDR; + + prcm_fmask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FMASK; + prcm_imask_mask[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IMASK; + prcm_fmask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_FADDR; + prcm_imask_addr[PRCM_REG_CORE_CLK2] = PRCM_REG_CORE_CLK2_IADDR; + + prcm_fmask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FMASK; + prcm_imask_mask[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IMASK; + prcm_fmask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_FADDR; + prcm_imask_addr[PRCM_REG_CORE_CLK3] = PRCM_REG_CORE_CLK3_IADDR; + + prcm_fmask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FMASK; + prcm_imask_mask[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IMASK; + prcm_fmask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_FADDR; + prcm_imask_addr[PRCM_REG_USBHOST] = PRCM_REG_USBHOST_IADDR; +} + +void +prcm_setclock(int clock, int speed) +{ + struct prcm_softc *sc = prcm_cd.cd_devs[0]; + + if (!sc->sc_setclock) + panic("%s: not initialised!", __func__); + + sc->sc_setclock(sc, clock, speed); +} + +void +prcm_am335x_setclock(struct prcm_softc *sc, int clock, int speed) +{ + u_int32_t oreg, reg, mask; + + /* set CLKSEL register */ + if (clock == 1) { + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, + PRCM_AM335X_CLKSEL_TIMER2_CLK); + mask = 3; + reg = oreg & ~mask; + reg |=0x02; + bus_space_write_4(sc->sc_iot, sc->sc_prcm, + PRCM_AM335X_CLKSEL_TIMER2_CLK, reg); + } else if (clock == 2) { + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, + PRCM_AM335X_CLKSEL_TIMER3_CLK); + mask = 3; + reg = oreg & ~mask; + reg |=0x02; + bus_space_write_4(sc->sc_iot, sc->sc_prcm, + PRCM_AM335X_CLKSEL_TIMER3_CLK, reg); + } +} + +void +prcm_v3_setclock(struct prcm_softc *sc, int clock, int speed) +{ + u_int32_t oreg, reg, mask; + + if (clock == 1) { + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP); + mask = 1; + reg = (oreg &~mask) | (speed & mask); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_WKUP, reg); + } else if (clock >= 2 && clock <= 9) { + int shift = (clock-2); + oreg = bus_space_read_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER); + mask = 1 << (shift); + reg = (oreg & ~mask) | ( (speed << shift) & mask); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL_PER, reg); + } else + panic("%s: invalid clock %d", __func__, clock); +} + +uint32_t +prcm_v3_bit(int mod) +{ + switch(mod) { + case PRCM_MMC: + return PRCM_CLK_EN_MMC1; + case PRCM_USB: + return PRCM_CLK_EN_USB; + default: + panic("%s: module not found\n", __func__); + } +} + +uint32_t +prcm_am335x_clkctrl(int mod) +{ + switch(mod) { + case PRCM_TIMER2: + return PRCM_AM335X_TIMER2_CLKCTRL; + case PRCM_TIMER3: + return PRCM_AM335X_TIMER3_CLKCTRL; + case PRCM_MMC: + return PRCM_AM335X_MMC0_CLKCTRL; + case PRCM_USB: + return PRCM_AM335X_USB0_CLKCTRL; + default: + panic("%s: module not found\n", __func__); + } +} + +void +prcm_enablemodule(int mod) +{ + struct prcm_softc *sc = prcm_cd.cd_devs[0]; + + if (!sc->sc_enablemodule) + panic("%s: not initialised!", __func__); + + sc->sc_enablemodule(sc, mod); +} + +void +prcm_am335x_enablemodule(struct prcm_softc *sc, int mod) +{ + uint32_t clkctrl; + int reg; + + /*set enable bits in CLKCTRL register */ + reg = prcm_am335x_clkctrl(mod); + clkctrl = bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg); + clkctrl &=~AM335X_CLKCTRL_MODULEMODE_MASK; + clkctrl |= AM335X_CLKCTRL_MODULEMODE_ENABLE; + bus_space_write_4(sc->sc_iot, sc->sc_prcm, reg, clkctrl); + + /* wait until module is enabled */ + while (bus_space_read_4(sc->sc_iot, sc->sc_prcm, reg) & 0x30000) + ; +} + +void +prcm_v3_enablemodule(struct prcm_softc *sc, int mod) +{ + uint32_t bit; + uint32_t fclk, iclk, fmask, imask, mbit; + int freg, ireg, reg; + + bit = prcm_v3_bit(mod); + reg = bit >> 5; + + freg = prcm_fmask_addr[reg]; + ireg = prcm_imask_addr[reg]; + fmask = prcm_fmask_mask[reg]; + imask = prcm_imask_mask[reg]; + + mbit = 1 << (bit & 0x1f); + if (fmask & mbit) { /* dont access the register if bit isn't present */ + fclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, freg); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, freg, fclk | mbit); + } + if (imask & mbit) { /* dont access the register if bit isn't present */ + iclk = bus_space_read_4(sc->sc_iot, sc->sc_prcm, ireg); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, ireg, iclk | mbit); + } + printf("\n"); +} + +void +prcm_v4_enablemodule(struct prcm_softc *sc, int mod) +{ + switch (mod) { + case PRCM_USBP1_PHY: + case PRCM_USBP2_PHY: + prcm_v4_hsusbhost_set_source(mod, 0); + case PRCM_USB: + case PRCM_USBTLL: + case PRCM_USBP1_UTMI: + case PRCM_USBP1_HSIC: + case PRCM_USBP2_UTMI: + case PRCM_USBP2_HSIC: + prcm_v4_hsusbhost_activate(mod); + return; + default: + panic("%s: module not found\n", __func__); + } +} + +int +prcm_v4_hsusbhost_activate(int type) +{ + struct prcm_softc *sc = prcm_cd.cd_devs[0]; + uint32_t i; + uint32_t clksel_reg_off; + uint32_t clksel, oclksel; + + switch (type) { + case PRCM_USB: + case PRCM_USBP1_PHY: + case PRCM_USBP2_PHY: + /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */ + clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58; + clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off); + oclksel = clksel; + /* Enable the module and also enable the optional func clocks */ + if (type == PRCM_USB) { + clksel &= ~O4_CLKCTRL_MODULEMODE_MASK; + clksel |= /*O4_CLKCTRL_MODULEMODE_ENABLE*/2; + + clksel |= (0x1 << 15); /* USB-HOST clock control: FUNC48MCLK */ + } + + break; + + default: + panic("%s: invalid type %d", type); + return (EINVAL); + } + bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel); + + /* Try MAX_MODULE_ENABLE_WAIT number of times to check if enabled */ + for (i = 0; i < O4_MAX_MODULE_ENABLE_WAIT; i++) { + clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off); + if ((clksel & O4_CLKCTRL_IDLEST_MASK) == O4_CLKCTRL_IDLEST_ENABLED) + break; + } + + /* Check the enabled state */ + if ((clksel & O4_CLKCTRL_IDLEST_MASK) != O4_CLKCTRL_IDLEST_ENABLED) { + printf("Error: HERE failed to enable module with clock %d\n", type); + printf("Error: 0x%08x => 0x%08x\n", clksel_reg_off, clksel); + return (ETIMEDOUT); + } + + return (0); +} + +int +prcm_v4_hsusbhost_set_source(int clk, int clksrc) +{ + struct prcm_softc *sc = prcm_cd.cd_devs[0]; + uint32_t clksel_reg_off; + uint32_t clksel; + unsigned int bit; + + if (clk == PRCM_USBP1_PHY) + bit = 24; + else if (clk != PRCM_USBP2_PHY) + bit = 25; + else + return (-EINVAL); + + /* We need the CM_L3INIT_HSUSBHOST_CLKCTRL register in CM2 register set */ + clksel_reg_off = O4_L3INIT_CM2_OFFSET + 0x58; + clksel = bus_space_read_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off); + + /* XXX: Set the clock source to either external or internal */ + if (clksrc == 0) + clksel |= (0x1 << bit); + else + clksel &= ~(0x1 << bit); + + bus_space_write_4(sc->sc_iot, sc->sc_cm2, clksel_reg_off, clksel); + + return (0); +} + +/* + * OMAP35xx Power, Reset, and Clock Management Reference Guide + * (sprufa5.pdf) and AM/DM37x Multimedia Device Technical Reference + * Manual (sprugn4h.pdf) note that DPLL5 provides a 120MHz clock for + * peripheral domain modules (page 107 and page 302). + * The reference clock for DPLL5 is DPLL5_ALWON_FCLK which is + * SYS_CLK, running at 13MHz. + */ +int +prcm_setup_dpll5(struct prcm_softc *sc) +{ + uint32_t val; + + /* + * We need to set the multiplier and divider values for PLL. + * To end up with 120MHz we take SYS_CLK, divide by it and multiply + * with 120 (sprugn4h.pdf, 13.4.11.4.1 SSC Configuration) + */ + val = ((120 & 0x7ff) << 8) | ((SYS_CLK - 1) & 0x7f); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL4_PLL, val); + + /* Clock divider from the PLL to the 120MHz clock. */ + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKSEL5_PLL, val); + + /* + * spruf98o.pdf, page 2319: + * PERIPH2_DPLL_FREQSEL is 0x7 1.75MHz to 2.1MHz + * EN_PERIPH2_DPLL is 0x7 + */ + val = (7 << 4) | (7 << 0); + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_CLKEN2_PLL, val); + + /* Disable the interconnect clock auto-idle. */ + bus_space_write_4(sc->sc_iot, sc->sc_prcm, CM_AUTOIDLE2_PLL, 0x0); + + /* Wait until DPLL5 is locked and there's clock activity. */ + while ((val = bus_space_read_4(sc->sc_iot, sc->sc_prcm, + CM_IDLEST_CKGEN) & 0x01) == 0x00) { +#ifdef DIAGNOSTIC + printf("CM_IDLEST_PLL = 0x%08x\n", val); +#endif + } + + return 0; +} diff --git a/sys/arch/armv7/omap/prcmvar.h b/sys/arch/armv7/omap/prcmvar.h new file mode 100644 index 00000000000..c3070b4ac8e --- /dev/null +++ b/sys/arch/armv7/omap/prcmvar.h @@ -0,0 +1,42 @@ +/* $OpenBSD: prcmvar.h,v 1.1 2013/09/04 14:38:32 patrick Exp $ */ +/* + * Copyright (c) 2007,2009 Dale Rahn <drahn@openbsd.org> + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + */ + +void prcm_setclock(int clock, int speed); +void prcm_enablemodule(int mod); +void prcm_disablemodule(int mod); + +#define PRCM_CLK_SPEED_32 0 +#define PRCM_CLK_SPEED_SYS 1 + +enum PRCM_MODULES { + PRCM_TIMER0, + PRCM_TIMER1, + PRCM_TIMER2, + PRCM_TIMER3, + PRCM_MMC, + PRCM_USB, + PRCM_USBTLL, + PRCM_USBP1_PHY, + PRCM_USBP1_UTMI, + PRCM_USBP1_HSIC, + PRCM_USBP2_PHY, + PRCM_USBP2_UTMI, + PRCM_USBP2_HSIC +}; + +#define PRCM_REG_MAX 6 +/* need interface for CM_AUTOIDLE */ diff --git a/sys/arch/armv7/omap/sitara_cm.c b/sys/arch/armv7/omap/sitara_cm.c new file mode 100644 index 00000000000..4b493fb78d7 --- /dev/null +++ b/sys/arch/armv7/omap/sitara_cm.c @@ -0,0 +1,394 @@ +/* $OpenBSD: sitara_cm.c,v 1.1 2013/09/04 14:38:32 patrick Exp $ */ +/* $NetBSD: sitara_cm.c,v 1.1 2013/04/17 14:31:02 bouyer Exp $ */ +/* + * Copyright (c) 2010 + * Ben Gray <ben.r.gray@gmail.com>. + * All rights reserved. + * + * 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 by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + */ + +/* + * SCM - System Control Module + * + * Hopefully in the end this module will contain a bunch of utility functions + * for configuring and querying the general system control registers, but for + * now it only does pin(pad) multiplexing. + * + * This is different from the GPIO module in that it is used to configure the + * pins between modules not just GPIO input/output. + * + * This file contains the generic top level driver, however it relies on chip + * specific settings and therefore expects an array of sitara_cm_padconf structs + * call ti_padconf_devmap to be located somewhere in the kernel. + * + */ +#include <sys/types.h> +#include <sys/cdefs.h> +#include <sys/param.h> +#include <sys/systm.h> +#include <sys/kernel.h> +#include <sys/device.h> +#include <sys/conf.h> +#include <sys/proc.h> +#include <machine/bus.h> + +#include <armv7/omap/omapvar.h> +#include <armv7/omap/sitara_cm.h> +#include <armv7/omap/sitara_cmreg.h> + +void sitara_cm_attach(struct device *parent, struct device *self, void *aux); + +struct sitara_cm_softc { + struct device sc_dev; + bus_space_tag_t sc_iot; + bus_space_handle_t sc_ioh; +}; + +struct cfattach sitaracm_ca = { + sizeof (struct sitara_cm_softc), NULL, sitara_cm_attach +}; + +struct cfdriver sitaracm_cd = { + NULL, "sitaracm", DV_DULL +}; + +static struct sitara_cm_softc *sitara_cm_sc = NULL; + +#define sitara_cm_read_2(sc, reg) \ + bus_space_read_2((sc)->sc_iot, (sc)->sc_ioh, (reg)) +#define sitara_cm_write_2(sc, reg, val) \ + bus_space_write_2((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) +#define sitara_cm_read_4(sc, reg) \ + bus_space_read_4((sc)->sc_iot, (sc)->sc_ioh, (reg)) +#define sitara_cm_write_4(sc, reg, val) \ + bus_space_write_4((sc)->sc_iot, (sc)->sc_ioh, (reg), (val)) + + +/** + * ti_padconf_devmap - Array of pins, should be defined one per SoC + * + * This array is typically defined in one of the targeted *_scm_pinumx.c + * files and is specific to the given SoC platform. Each entry in the array + * corresponds to an individual pin. + */ +extern const struct sitara_cm_device sitara_cm_dev; + + +/** + * sitara_cm_padconf_from_name - searches the list of pads and returns entry + * with matching ball name. + * @ballname: the name of the ball + * + * RETURNS: + * A pointer to the matching padconf or NULL if the ball wasn't found. + */ +static const struct sitara_cm_padconf* +sitara_cm_padconf_from_name(const char *ballname) +{ + const struct sitara_cm_padconf *padconf; + + padconf = sitara_cm_dev.padconf; + while (padconf->ballname != NULL) { + if (strcmp(ballname, padconf->ballname) == 0) + return(padconf); + padconf++; + } + + return (NULL); +} + +/** + * sitara_cm_padconf_set_internal - sets the muxmode and state for a pad/pin + * @padconf: pointer to the pad structure + * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx" + * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_??? + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or already in use. + */ +static int +sitara_cm_padconf_set_internal(struct sitara_cm_softc *sc, + const struct sitara_cm_padconf *padconf, + const char *muxmode, unsigned int state) +{ + unsigned int mode; + uint16_t reg_val; + + /* populate the new value for the PADCONF register */ + reg_val = (uint16_t)(state & sitara_cm_dev.padconf_sate_mask); + + /* find the new mode requested */ + for (mode = 0; mode < 8; mode++) { + if ((padconf->muxmodes[mode] != NULL) && + (strcmp(padconf->muxmodes[mode], muxmode) == 0)) { + break; + } + } + + /* couldn't find the mux mode */ + if (mode >= 8) { + printf("%s: Invalid mux mode \"%s\"\n", __func__, muxmode); + return (EINVAL); + } + + /* set the mux mode */ + reg_val |= (uint16_t)(mode & sitara_cm_dev.padconf_muxmode_mask); + + /* write the register value (16-bit writes) */ + sitara_cm_write_2(sc, padconf->reg_off, reg_val); + + return (0); +} + +/** + * sitara_cm_padconf_set - sets the muxmode and state for a pad/pin + * @padname: the name of the pad, i.e. "c12" + * @muxmode: the name of the mode to use for the pin, i.e. "uart1_rx" + * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_??? + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or already in use. + */ +int +sitara_cm_padconf_set(const char *padname, const char *muxmode, unsigned int state) +{ + const struct sitara_cm_padconf *padconf; + + if (!sitara_cm_sc) + return (ENXIO); + + /* find the pin in the devmap */ + padconf = sitara_cm_padconf_from_name(padname); + if (padconf == NULL) + return (EINVAL); + + return ( + sitara_cm_padconf_set_internal(sitara_cm_sc, padconf, muxmode, state) + ); +} + +/** + * sitara_cm_padconf_get - gets the muxmode and state for a pad/pin + * @padname: the name of the pad, i.e. "c12" + * @muxmode: upon return will contain the name of the muxmode of the pin + * @state: upon return will contain the state of the pad/pin + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or already in use. + */ +int +sitara_cm_padconf_get(const char *padname, const char **muxmode, + unsigned int *state) +{ + const struct sitara_cm_padconf *padconf; + uint16_t reg_val; + + if (!sitara_cm_sc) + return (ENXIO); + + /* find the pin in the devmap */ + padconf = sitara_cm_padconf_from_name(padname); + if (padconf == NULL) + return (EINVAL); + + /* read the register value (16-bit reads) */ + reg_val = sitara_cm_read_2(sitara_cm_sc, padconf->reg_off); + + /* save the state */ + if (state) + *state = (reg_val & sitara_cm_dev.padconf_sate_mask); + + /* save the mode */ + if (muxmode) { + *muxmode = padconf->muxmodes[ + (reg_val & sitara_cm_dev.padconf_muxmode_mask) + ]; + } + + return (0); +} + +/** + * sitara_cm_padconf_set_gpiomode - converts a pad to GPIO mode. + * @gpio: the GPIO pin number (0-195) + * @state: the state to put the pad/pin in, i.e. PADCONF_PIN_??? + * + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or already in use. + */ +int +sitara_cm_padconf_set_gpiomode(uint32_t gpio, unsigned int state) +{ + const struct sitara_cm_padconf *padconf; + uint16_t reg_val; + + if (!sitara_cm_sc) + return (ENXIO); + + /* find the gpio pin in the padconf array */ + padconf = sitara_cm_dev.padconf; + while (padconf->ballname != NULL) { + if (padconf->gpio_pin == gpio) + break; + padconf++; + } + if (padconf->ballname == NULL) + return (EINVAL); + + /* populate the new value for the PADCONF register */ + reg_val = (uint16_t)(state & sitara_cm_dev.padconf_sate_mask); + + /* set the mux mode */ + reg_val |= + (uint16_t)(padconf->gpio_mode & sitara_cm_dev.padconf_muxmode_mask); + + /* write the register value (16-bit writes) */ + sitara_cm_write_2(sitara_cm_sc, padconf->reg_off, reg_val); + + return (0); +} + +/** + * sitara_cm_padconf_get_gpiomode - gets the current GPIO mode of the pin + * @gpio: the GPIO pin number (0-195) + * @state: upon return will contain the state + * + * + * + * LOCKING: + * Internally locks it's own context. + * + * RETURNS: + * 0 on success. + * EINVAL if pin requested is outside valid range or not configured as GPIO. + */ +int +sitara_cm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state) +{ + const struct sitara_cm_padconf *padconf; + uint16_t reg_val; + + if (!sitara_cm_sc) + return (ENXIO); + + /* find the gpio pin in the padconf array */ + padconf = sitara_cm_dev.padconf; + while (padconf->ballname != NULL) { + if (padconf->gpio_pin == gpio) + break; + padconf++; + } + if (padconf->ballname == NULL) + return (EINVAL); + + /* read the current register settings */ + reg_val = sitara_cm_read_2(sitara_cm_sc, padconf->reg_off); + + /* + * check to make sure the pins is configured as GPIO in the + * first state + */ + if ((reg_val & sitara_cm_dev.padconf_muxmode_mask) != + padconf->gpio_mode) + return (EINVAL); + + /* + * read and store the reset of the state, + * i.e. pull-up, pull-down, etc + */ + if (state) + *state = (reg_val & sitara_cm_dev.padconf_sate_mask); + + return (0); +} + + +int +sitara_cm_reg_read_4(uint32_t reg, uint32_t *val) +{ + if (!sitara_cm_sc) + return (ENXIO); + + *val = sitara_cm_read_4(sitara_cm_sc, reg); + return (0); +} + +int +sitara_cm_reg_write_4(uint32_t reg, uint32_t val) +{ + if (!sitara_cm_sc) + return (ENXIO); + + sitara_cm_write_4(sitara_cm_sc, reg, val); + return (0); +} + +void +sitara_cm_attach(struct device *parent, struct device *self, void *aux) +{ + struct sitara_cm_softc *sc = (struct sitara_cm_softc *)self; + struct omap_attach_args *oa = aux; + uint32_t rev; + + if (sitara_cm_sc) + panic("sitara_cm_attach: already attached"); + + sc->sc_iot = oa->oa_iot; + + if (bus_space_map(oa->oa_iot, oa->oa_dev->mem[0].addr, + oa->oa_dev->mem[0].size, 0, &sc->sc_ioh) != 0) + panic("%s: bus_space_map failed!\n", __func__); + + sitara_cm_sc = sc; + + if (sitara_cm_reg_read_4(OMAP2SCM_REVISION, &rev) != 0) + panic("sitara_cm_attach: read revision"); + printf(": control module, rev %d.%d\n", + SCM_REVISION_MAJOR(rev), SCM_REVISION_MINOR(rev)); +} diff --git a/sys/arch/armv7/omap/sitara_cm.h b/sys/arch/armv7/omap/sitara_cm.h new file mode 100644 index 00000000000..96be9673d0b --- /dev/null +++ b/sys/arch/armv7/omap/sitara_cm.h @@ -0,0 +1,78 @@ +/* $OpenBSD: sitara_cm.h,v 1.1 2013/09/04 14:38:32 patrick Exp $ */ +/* $NetBSD: sitara_cm.h,v 1.1 2013/04/17 14:31:02 bouyer Exp $ */ +/* + * Copyright (c) 2010 + * Ben Gray <ben.r.gray@gmail.com>. + * All rights reserved. + * + * 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 by Ben Gray. + * 4. The name of the company nor the name of the author may be used to + * endorse or promote products derived from this software without specific + * prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``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 BEN GRAY 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. + * + */ + + +/** + * Functions to configure the PIN multiplexing on the chip. + * + * This is different from the GPIO module in that it is used to configure the + * pins between modules not just GPIO input output. + * + */ +#ifndef _OMAP_SCM_H_ +#define _OMAP_SCM_H_ + +struct sitara_cm_padconf { + uint16_t reg_off; + uint16_t gpio_pin; + uint16_t gpio_mode; + const char *ballname; + const char *muxmodes[8]; +}; + +struct sitara_cm_padstate { + const char *state; + uint16_t reg; +}; + +struct sitara_cm_device { + uint16_t padconf_muxmode_mask; + uint16_t padconf_sate_mask; + struct sitara_cm_padstate *padstate; + struct sitara_cm_padconf *padconf; +}; + +int sitara_cm_padconf_set(const char *padname, const char *muxmode, + unsigned int state); +int sitara_cm_padconf_get(const char *padname, const char **muxmode, + unsigned int *state); +int sitara_cm_padconf_set_gpiomode(uint32_t gpio, unsigned int state); +int sitara_cm_padconf_get_gpiomode(uint32_t gpio, unsigned int *state); +int sitara_cm_padconf_set_gpioflags(uint32_t gpio, uint32_t flags); +void sitara_cm_padconf_get_gpioflags(uint32_t gpio, uint32_t *flags); +int sitara_cm_reg_read_4(uint32_t reg, uint32_t *val); +int sitara_cm_reg_write_4(uint32_t reg, uint32_t val); + +#endif /* _OMAP_SCM_H_ */ diff --git a/sys/arch/armv7/omap/sitara_cmreg.h b/sys/arch/armv7/omap/sitara_cmreg.h new file mode 100644 index 00000000000..65aeeeb53da --- /dev/null +++ b/sys/arch/armv7/omap/sitara_cmreg.h @@ -0,0 +1,46 @@ +/* $OpenBSD: sitara_cmreg.h,v 1.1 2013/09/04 14:38:32 patrick Exp $ */ +/* $NetBSD: sitara_cmreg.h,v 1.1 2013/04/17 15:04:39 bouyer Exp $ */ + +/* + * Copyright (c) 2013 Manuel Bouyer. All rights reserved. + * + * 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. + * + * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 THE AUTHOR 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. + */ + +/* register definitions for the Control module found in the + * Texas Instrument AM335x SOC + */ + +#ifndef _OMAP2SCMREG_H +#define _OMAP2SCMREG_H + +#define OMAP2SCM_REVISION 0x0000 +#define SCM_REVISION_SCHEME(x) (((x) & 0xc0000000) >> 30) +#define SCM_REVISION_FUNC(x) (((x) & 0x0fff0000) >> 16) +#define SCM_REVISION_RTL(x) (((x) & 0x0000f800) >> 11) +#define SCM_REVISION_MAJOR(x) (((x) & 0x00000700) >> 8) +#define SCM_REVISION_CUSTOM(x) (((x) & 0x000000c0) >> 6) +#define SCM_REVISION_MINOR(x) (((x) & 0x0000001f) >> 0) + +#define OMAP2SCM_MAC_ID0_LO 0x630 +#define OMAP2SCM_MAC_ID0_HI 0x634 + +#endif /* _OMAP2SCMREG_H */ |