Index: head/sys/arm/ti/am335x/am335x_prcm.c =================================================================== --- head/sys/arm/ti/am335x/am335x_prcm.c (revision 297394) +++ head/sys/arm/ti/am335x/am335x_prcm.c (revision 297395) @@ -1,845 +1,855 @@ /*- * Copyright (c) 2012 Damjan Marion * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define CM_PER 0 #define CM_PER_L4LS_CLKSTCTRL (CM_PER + 0x000) #define CM_PER_L3S_CLKSTCTRL (CM_PER + 0x004) #define CM_PER_L3_CLKSTCTRL (CM_PER + 0x00C) #define CM_PER_CPGMAC0_CLKCTRL (CM_PER + 0x014) #define CM_PER_LCDC_CLKCTRL (CM_PER + 0x018) #define CM_PER_USB0_CLKCTRL (CM_PER + 0x01C) #define CM_PER_TPTC0_CLKCTRL (CM_PER + 0x024) #define CM_PER_UART5_CLKCTRL (CM_PER + 0x038) #define CM_PER_MMC0_CLKCTRL (CM_PER + 0x03C) #define CM_PER_I2C2_CLKCTRL (CM_PER + 0x044) #define CM_PER_I2C1_CLKCTRL (CM_PER + 0x048) +#define CM_PER_SPI0_CLKCTRL (CM_PER + 0x04C) +#define CM_PER_SPI1_CLKCTRL (CM_PER + 0x050) #define CM_PER_UART1_CLKCTRL (CM_PER + 0x06C) #define CM_PER_UART2_CLKCTRL (CM_PER + 0x070) #define CM_PER_UART3_CLKCTRL (CM_PER + 0x074) #define CM_PER_UART4_CLKCTRL (CM_PER + 0x078) #define CM_PER_TIMER7_CLKCTRL (CM_PER + 0x07C) #define CM_PER_TIMER2_CLKCTRL (CM_PER + 0x080) #define CM_PER_TIMER3_CLKCTRL (CM_PER + 0x084) #define CM_PER_TIMER4_CLKCTRL (CM_PER + 0x088) #define CM_PER_GPIO1_CLKCTRL (CM_PER + 0x0AC) #define CM_PER_GPIO2_CLKCTRL (CM_PER + 0x0B0) #define CM_PER_GPIO3_CLKCTRL (CM_PER + 0x0B4) #define CM_PER_TPCC_CLKCTRL (CM_PER + 0x0BC) #define CM_PER_EPWMSS1_CLKCTRL (CM_PER + 0x0CC) #define CM_PER_EPWMSS0_CLKCTRL (CM_PER + 0x0D4) #define CM_PER_EPWMSS2_CLKCTRL (CM_PER + 0x0D8) #define CM_PER_L3_INSTR_CLKCTRL (CM_PER + 0x0DC) #define CM_PER_L3_CLKCTRL (CM_PER + 0x0E0) #define CM_PER_PRUSS_CLKCTRL (CM_PER + 0x0E8) #define CM_PER_TIMER5_CLKCTRL (CM_PER + 0x0EC) #define CM_PER_TIMER6_CLKCTRL (CM_PER + 0x0F0) #define CM_PER_MMC1_CLKCTRL (CM_PER + 0x0F4) #define CM_PER_MMC2_CLKCTRL (CM_PER + 0x0F8) #define CM_PER_TPTC1_CLKCTRL (CM_PER + 0x0FC) #define CM_PER_TPTC2_CLKCTRL (CM_PER + 0x100) #define CM_PER_SPINLOCK0_CLKCTRL (CM_PER + 0x10C) #define CM_PER_MAILBOX0_CLKCTRL (CM_PER + 0x110) #define CM_PER_OCPWP_L3_CLKSTCTRL (CM_PER + 0x12C) #define CM_PER_OCPWP_CLKCTRL (CM_PER + 0x130) #define CM_PER_CPSW_CLKSTCTRL (CM_PER + 0x144) #define CM_PER_PRUSS_CLKSTCTRL (CM_PER + 0x140) #define CM_WKUP 0x400 #define CM_WKUP_CLKSTCTRL (CM_WKUP + 0x000) #define CM_WKUP_CONTROL_CLKCTRL (CM_WKUP + 0x004) #define CM_WKUP_GPIO0_CLKCTRL (CM_WKUP + 0x008) #define CM_WKUP_CM_L3_AON_CLKSTCTRL (CM_WKUP + 0x01C) #define CM_WKUP_CM_CLKSEL_DPLL_MPU (CM_WKUP + 0x02C) #define CM_WKUP_CM_IDLEST_DPLL_DISP (CM_WKUP + 0x048) #define CM_WKUP_CM_CLKSEL_DPLL_DISP (CM_WKUP + 0x054) #define CM_WKUP_CM_CLKDCOLDO_DPLL_PER (CM_WKUP + 0x07C) #define CM_WKUP_CM_CLKMODE_DPLL_DISP (CM_WKUP + 0x098) #define CM_WKUP_I2C0_CLKCTRL (CM_WKUP + 0x0B8) #define CM_WKUP_ADC_TSC_CLKCTRL (CM_WKUP + 0x0BC) #define CM_DPLL 0x500 #define CLKSEL_TIMER7_CLK (CM_DPLL + 0x004) #define CLKSEL_TIMER2_CLK (CM_DPLL + 0x008) #define CLKSEL_TIMER3_CLK (CM_DPLL + 0x00C) #define CLKSEL_TIMER4_CLK (CM_DPLL + 0x010) #define CLKSEL_TIMER5_CLK (CM_DPLL + 0x018) #define CLKSEL_TIMER6_CLK (CM_DPLL + 0x01C) #define CLKSEL_PRUSS_OCP_CLK (CM_DPLL + 0x030) #define CM_RTC 0x800 #define CM_RTC_RTC_CLKCTRL (CM_RTC + 0x000) #define CM_RTC_CLKSTCTRL (CM_RTC + 0x004) #define PRM_PER 0xC00 #define PRM_PER_RSTCTRL (PRM_PER + 0x00) #define PRM_DEVICE_OFFSET 0xF00 #define PRM_RSTCTRL (PRM_DEVICE_OFFSET + 0x00) struct am335x_prcm_softc { struct resource * res[2]; bus_space_tag_t bst; bus_space_handle_t bsh; }; static struct resource_spec am335x_prcm_spec[] = { { SYS_RES_MEMORY, 0, RF_ACTIVE }, { -1, 0 } }; static struct am335x_prcm_softc *am335x_prcm_sc = NULL; static int am335x_clk_noop_activate(struct ti_clock_dev *clkdev); static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev); static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev); static int am335x_clk_noop_deactivate(struct ti_clock_dev *clkdev); static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev); static int am335x_clk_noop_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc); static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq); static int am335x_clk_set_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int freq); static void am335x_prcm_reset(void); static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev); static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev); static int am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev); static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev); #define AM335X_NOOP_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = am335x_clk_noop_activate, \ .clk_deactivate = am335x_clk_noop_deactivate, \ .clk_set_source = am335x_clk_noop_set_source, \ .clk_accessible = NULL, \ .clk_get_source_freq = NULL, \ .clk_set_source_freq = NULL \ } #define AM335X_GENERIC_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = am335x_clk_generic_activate, \ .clk_deactivate = am335x_clk_generic_deactivate, \ .clk_set_source = am335x_clk_generic_set_source, \ .clk_accessible = NULL, \ .clk_get_source_freq = NULL, \ .clk_set_source_freq = NULL \ } #define AM335X_GPIO_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = am335x_clk_gpio_activate, \ .clk_deactivate = am335x_clk_generic_deactivate, \ .clk_set_source = am335x_clk_generic_set_source, \ .clk_accessible = NULL, \ .clk_get_source_freq = NULL, \ .clk_set_source_freq = NULL \ } #define AM335X_MMCHS_CLOCK_DEV(i) \ { .id = (i), \ .clk_activate = am335x_clk_generic_activate, \ .clk_deactivate = am335x_clk_generic_deactivate, \ .clk_set_source = am335x_clk_generic_set_source, \ .clk_accessible = NULL, \ .clk_get_source_freq = am335x_clk_hsmmc_get_source_freq, \ .clk_set_source_freq = NULL \ } struct ti_clock_dev ti_am335x_clk_devmap[] = { /* System clocks */ { .id = SYS_CLK, .clk_activate = NULL, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = am335x_clk_get_sysclk_freq, .clk_set_source_freq = NULL, }, /* MPU (ARM) core clocks */ { .id = MPU_CLK, .clk_activate = NULL, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = am335x_clk_get_arm_fclk_freq, .clk_set_source_freq = NULL, }, /* CPSW Ethernet Switch core clocks */ { .id = CPSW_CLK, .clk_activate = am335x_clk_cpsw_activate, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = NULL, .clk_set_source_freq = NULL, }, /* Mentor USB HS controller core clocks */ { .id = MUSB0_CLK, .clk_activate = am335x_clk_musb0_activate, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = NULL, .clk_set_source_freq = NULL, }, /* LCD controller clocks */ { .id = LCDC_CLK, .clk_activate = am335x_clk_lcdc_activate, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = am335x_clk_get_arm_disp_freq, .clk_set_source_freq = am335x_clk_set_arm_disp_freq, }, /* UART */ AM335X_NOOP_CLOCK_DEV(UART1_CLK), AM335X_GENERIC_CLOCK_DEV(UART2_CLK), AM335X_GENERIC_CLOCK_DEV(UART3_CLK), AM335X_GENERIC_CLOCK_DEV(UART4_CLK), AM335X_GENERIC_CLOCK_DEV(UART5_CLK), AM335X_GENERIC_CLOCK_DEV(UART6_CLK), /* DMTimer */ AM335X_GENERIC_CLOCK_DEV(TIMER2_CLK), AM335X_GENERIC_CLOCK_DEV(TIMER3_CLK), AM335X_GENERIC_CLOCK_DEV(TIMER4_CLK), AM335X_GENERIC_CLOCK_DEV(TIMER5_CLK), AM335X_GENERIC_CLOCK_DEV(TIMER6_CLK), AM335X_GENERIC_CLOCK_DEV(TIMER7_CLK), /* GPIO, we use hwmods as reference, not units in spec */ AM335X_GPIO_CLOCK_DEV(GPIO1_CLK), AM335X_GPIO_CLOCK_DEV(GPIO2_CLK), AM335X_GPIO_CLOCK_DEV(GPIO3_CLK), AM335X_GPIO_CLOCK_DEV(GPIO4_CLK), /* I2C we use hwmods as reference, not units in spec */ AM335X_GENERIC_CLOCK_DEV(I2C1_CLK), AM335X_GENERIC_CLOCK_DEV(I2C2_CLK), AM335X_GENERIC_CLOCK_DEV(I2C3_CLK), + /* McSPI we use hwmods as reference, not units in spec */ + AM335X_GENERIC_CLOCK_DEV(SPI0_CLK), + AM335X_GENERIC_CLOCK_DEV(SPI1_CLK), + /* TSC_ADC */ AM335X_GENERIC_CLOCK_DEV(TSC_ADC_CLK), /* EDMA */ AM335X_GENERIC_CLOCK_DEV(EDMA_TPCC_CLK), AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC0_CLK), AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC1_CLK), AM335X_GENERIC_CLOCK_DEV(EDMA_TPTC2_CLK), /* MMCHS */ AM335X_MMCHS_CLOCK_DEV(MMC1_CLK), AM335X_MMCHS_CLOCK_DEV(MMC2_CLK), AM335X_MMCHS_CLOCK_DEV(MMC3_CLK), /* PWMSS */ AM335X_GENERIC_CLOCK_DEV(PWMSS0_CLK), AM335X_GENERIC_CLOCK_DEV(PWMSS1_CLK), AM335X_GENERIC_CLOCK_DEV(PWMSS2_CLK), /* System Mailbox clock */ AM335X_GENERIC_CLOCK_DEV(MAILBOX0_CLK), /* SPINLOCK */ AM335X_GENERIC_CLOCK_DEV(SPINLOCK0_CLK), /* PRU-ICSS */ { .id = PRUSS_CLK, .clk_activate = am335x_clk_pruss_activate, .clk_deactivate = NULL, .clk_set_source = NULL, .clk_accessible = NULL, .clk_get_source_freq = NULL, .clk_set_source_freq = NULL, }, /* RTC */ AM335X_GENERIC_CLOCK_DEV(RTC_CLK), { INVALID_CLK_IDENT, NULL, NULL, NULL, NULL } }; struct am335x_clk_details { clk_ident_t id; uint32_t clkctrl_reg; uint32_t clksel_reg; }; #define _CLK_DETAIL(i, c, s) \ { .id = (i), \ .clkctrl_reg = (c), \ .clksel_reg = (s), \ } static struct am335x_clk_details g_am335x_clk_details[] = { /* UART. UART0 clock not controllable. */ _CLK_DETAIL(UART1_CLK, 0, 0), _CLK_DETAIL(UART2_CLK, CM_PER_UART1_CLKCTRL, 0), _CLK_DETAIL(UART3_CLK, CM_PER_UART2_CLKCTRL, 0), _CLK_DETAIL(UART4_CLK, CM_PER_UART3_CLKCTRL, 0), _CLK_DETAIL(UART5_CLK, CM_PER_UART4_CLKCTRL, 0), _CLK_DETAIL(UART6_CLK, CM_PER_UART5_CLKCTRL, 0), /* DMTimer modules */ _CLK_DETAIL(TIMER2_CLK, CM_PER_TIMER2_CLKCTRL, CLKSEL_TIMER2_CLK), _CLK_DETAIL(TIMER3_CLK, CM_PER_TIMER3_CLKCTRL, CLKSEL_TIMER3_CLK), _CLK_DETAIL(TIMER4_CLK, CM_PER_TIMER4_CLKCTRL, CLKSEL_TIMER4_CLK), _CLK_DETAIL(TIMER5_CLK, CM_PER_TIMER5_CLKCTRL, CLKSEL_TIMER5_CLK), _CLK_DETAIL(TIMER6_CLK, CM_PER_TIMER6_CLKCTRL, CLKSEL_TIMER6_CLK), _CLK_DETAIL(TIMER7_CLK, CM_PER_TIMER7_CLKCTRL, CLKSEL_TIMER7_CLK), /* GPIO modules, hwmods start with gpio1 */ _CLK_DETAIL(GPIO1_CLK, CM_WKUP_GPIO0_CLKCTRL, 0), _CLK_DETAIL(GPIO2_CLK, CM_PER_GPIO1_CLKCTRL, 0), _CLK_DETAIL(GPIO3_CLK, CM_PER_GPIO2_CLKCTRL, 0), _CLK_DETAIL(GPIO4_CLK, CM_PER_GPIO3_CLKCTRL, 0), /* I2C modules, hwmods start with i2c1 */ _CLK_DETAIL(I2C1_CLK, CM_WKUP_I2C0_CLKCTRL, 0), _CLK_DETAIL(I2C2_CLK, CM_PER_I2C1_CLKCTRL, 0), _CLK_DETAIL(I2C3_CLK, CM_PER_I2C2_CLKCTRL, 0), + + /* McSPI modules, hwmods start with spi0 */ + _CLK_DETAIL(SPI0_CLK, CM_PER_SPI0_CLKCTRL, 0), + _CLK_DETAIL(SPI1_CLK, CM_PER_SPI1_CLKCTRL, 0), /* TSC_ADC module */ _CLK_DETAIL(TSC_ADC_CLK, CM_WKUP_ADC_TSC_CLKCTRL, 0), /* EDMA modules */ _CLK_DETAIL(EDMA_TPCC_CLK, CM_PER_TPCC_CLKCTRL, 0), _CLK_DETAIL(EDMA_TPTC0_CLK, CM_PER_TPTC0_CLKCTRL, 0), _CLK_DETAIL(EDMA_TPTC1_CLK, CM_PER_TPTC1_CLKCTRL, 0), _CLK_DETAIL(EDMA_TPTC2_CLK, CM_PER_TPTC2_CLKCTRL, 0), /* MMCHS modules, hwmods start with mmc1*/ _CLK_DETAIL(MMC1_CLK, CM_PER_MMC0_CLKCTRL, 0), _CLK_DETAIL(MMC2_CLK, CM_PER_MMC1_CLKCTRL, 0), _CLK_DETAIL(MMC3_CLK, CM_PER_MMC1_CLKCTRL, 0), /* PWMSS modules */ _CLK_DETAIL(PWMSS0_CLK, CM_PER_EPWMSS0_CLKCTRL, 0), _CLK_DETAIL(PWMSS1_CLK, CM_PER_EPWMSS1_CLKCTRL, 0), _CLK_DETAIL(PWMSS2_CLK, CM_PER_EPWMSS2_CLKCTRL, 0), _CLK_DETAIL(MAILBOX0_CLK, CM_PER_MAILBOX0_CLKCTRL, 0), _CLK_DETAIL(SPINLOCK0_CLK, CM_PER_SPINLOCK0_CLKCTRL, 0), /* RTC module */ _CLK_DETAIL(RTC_CLK, CM_RTC_RTC_CLKCTRL, 0), { INVALID_CLK_IDENT, 0}, }; /* Read/Write macros */ #define prcm_read_4(reg) \ bus_space_read_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg) #define prcm_write_4(reg, val) \ bus_space_write_4(am335x_prcm_sc->bst, am335x_prcm_sc->bsh, reg, val) void am335x_prcm_setup_dmtimer(int); static int am335x_prcm_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) return (ENXIO); if (ofw_bus_is_compatible(dev, "ti,am3-prcm")) { device_set_desc(dev, "AM335x Power and Clock Management"); return(BUS_PROBE_DEFAULT); } return (ENXIO); } static int am335x_prcm_attach(device_t dev) { struct am335x_prcm_softc *sc = device_get_softc(dev); unsigned int sysclk, fclk; if (am335x_prcm_sc) return (ENXIO); if (bus_alloc_resources(dev, am335x_prcm_spec, sc->res)) { device_printf(dev, "could not allocate resources\n"); return (ENXIO); } sc->bst = rman_get_bustag(sc->res[0]); sc->bsh = rman_get_bushandle(sc->res[0]); am335x_prcm_sc = sc; ti_cpu_reset = am335x_prcm_reset; if (am335x_clk_get_sysclk_freq(NULL, &sysclk) != 0) sysclk = 0; if (am335x_clk_get_arm_fclk_freq(NULL, &fclk) != 0) fclk = 0; if (sysclk && fclk) device_printf(dev, "Clocks: System %u.%01u MHz, CPU %u MHz\n", sysclk/1000000, (sysclk % 1000000)/100000, fclk/1000000); else device_printf(dev, "can't read frequencies yet (SCM device not ready?)\n"); return (0); } static device_method_t am335x_prcm_methods[] = { DEVMETHOD(device_probe, am335x_prcm_probe), DEVMETHOD(device_attach, am335x_prcm_attach), { 0, 0 } }; static driver_t am335x_prcm_driver = { "am335x_prcm", am335x_prcm_methods, sizeof(struct am335x_prcm_softc), }; static devclass_t am335x_prcm_devclass; DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver, am335x_prcm_devclass, 0, 0); MODULE_VERSION(am335x_prcm, 1); MODULE_DEPEND(am335x_prcm, ti_scm, 1, 1, 1); static struct am335x_clk_details* am335x_clk_details(clk_ident_t id) { struct am335x_clk_details *walker; for (walker = g_am335x_clk_details; walker->id != INVALID_CLK_IDENT; walker++) { if (id == walker->id) return (walker); } return NULL; } static int am335x_clk_noop_activate(struct ti_clock_dev *clkdev) { return (0); } static int am335x_clk_generic_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; struct am335x_clk_details* clk_details; if (sc == NULL) return ENXIO; clk_details = am335x_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); /* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */ prcm_write_4(clk_details->clkctrl_reg, 2); while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 2) DELAY(10); return (0); } static int am335x_clk_gpio_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; struct am335x_clk_details* clk_details; if (sc == NULL) return ENXIO; clk_details = am335x_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); /* set *_CLKCTRL register MODULEMODE[1:0] to enable(2) */ /* set *_CLKCTRL register OPTFCLKEN_GPIO_1_G DBCLK[18] to FCLK_EN(1) */ prcm_write_4(clk_details->clkctrl_reg, 2 | (1 << 18)); while ((prcm_read_4(clk_details->clkctrl_reg) & (3 | (1 << 18) )) != (2 | (1 << 18))) DELAY(10); return (0); } static int am335x_clk_noop_deactivate(struct ti_clock_dev *clkdev) { return(0); } static int am335x_clk_generic_deactivate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; struct am335x_clk_details* clk_details; if (sc == NULL) return ENXIO; clk_details = am335x_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); /* set *_CLKCTRL register MODULEMODE[1:0] to disable(0) */ prcm_write_4(clk_details->clkctrl_reg, 0); while ((prcm_read_4(clk_details->clkctrl_reg) & 0x3) != 0) DELAY(10); return (0); } static int am335x_clk_noop_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) { return (0); } static int am335x_clk_generic_set_source(struct ti_clock_dev *clkdev, clk_src_t clksrc) { struct am335x_prcm_softc *sc = am335x_prcm_sc; struct am335x_clk_details* clk_details; uint32_t reg; if (sc == NULL) return ENXIO; clk_details = am335x_clk_details(clkdev->id); if (clk_details == NULL) return (ENXIO); switch (clksrc) { case EXT_CLK: reg = 0; /* SEL2: TCLKIN clock */ break; case SYSCLK_CLK: reg = 1; /* SEL1: CLK_M_OSC clock */ break; case F32KHZ_CLK: reg = 2; /* SEL3: CLK_32KHZ clock */ break; default: return (ENXIO); } prcm_write_4(clk_details->clksel_reg, reg); while ((prcm_read_4(clk_details->clksel_reg) & 0x3) != reg) DELAY(10); return (0); } static int am335x_clk_hsmmc_get_source_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { *freq = 96000000; return (0); } static int am335x_clk_get_sysclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { uint32_t ctrl_status; /* Read the input clock freq from the control module */ /* control_status reg (0x40) */ if (ti_scm_reg_read_4(0x40, &ctrl_status)) return ENXIO; switch ((ctrl_status>>22) & 0x3) { case 0x0: /* 19.2Mhz */ *freq = 19200000; break; case 0x1: /* 24Mhz */ *freq = 24000000; break; case 0x2: /* 25Mhz */ *freq = 25000000; break; case 0x3: /* 26Mhz */ *freq = 26000000; break; } return (0); } #define DPLL_BYP_CLKSEL(reg) ((reg>>23) & 1) #define DPLL_DIV(reg) ((reg & 0x7f)+1) #define DPLL_MULT(reg) ((reg>>8) & 0x7FF) #define DPLL_MAX_MUL 0x800 #define DPLL_MAX_DIV 0x80 static int am335x_clk_get_arm_fclk_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { uint32_t reg; uint32_t sysclk; reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_MPU); /*Check if we are running in bypass */ if (DPLL_BYP_CLKSEL(reg)) return ENXIO; am335x_clk_get_sysclk_freq(NULL, &sysclk); *freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg)); return(0); } static int am335x_clk_get_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int *freq) { uint32_t reg; uint32_t sysclk; reg = prcm_read_4(CM_WKUP_CM_CLKSEL_DPLL_DISP); /*Check if we are running in bypass */ if (DPLL_BYP_CLKSEL(reg)) return ENXIO; am335x_clk_get_sysclk_freq(NULL, &sysclk); *freq = DPLL_MULT(reg) * (sysclk / DPLL_DIV(reg)); return(0); } static int am335x_clk_set_arm_disp_freq(struct ti_clock_dev *clkdev, unsigned int freq) { uint32_t sysclk; uint32_t mul, div; uint32_t i, j; unsigned int delta, min_delta; am335x_clk_get_sysclk_freq(NULL, &sysclk); /* Bypass mode */ prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x4); /* Make sure it's in bypass mode */ while (!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP) & (1 << 8))) DELAY(10); /* Dumb and non-optimal implementation */ min_delta = freq; for (i = 1; i < DPLL_MAX_MUL; i++) { for (j = 1; j < DPLL_MAX_DIV; j++) { delta = abs(freq - i*(sysclk/j)); if (delta < min_delta) { mul = i; div = j; min_delta = delta; } if (min_delta == 0) break; } } prcm_write_4(CM_WKUP_CM_CLKSEL_DPLL_DISP, (mul << 8) | (div - 1)); /* Locked mode */ prcm_write_4(CM_WKUP_CM_CLKMODE_DPLL_DISP, 0x7); int timeout = 10000; while ((!(prcm_read_4(CM_WKUP_CM_IDLEST_DPLL_DISP) & (1 << 0))) && timeout--) DELAY(10); return(0); } static void am335x_prcm_reset(void) { prcm_write_4(PRM_RSTCTRL, (1<<1)); } static int am335x_clk_cpsw_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; if (sc == NULL) return ENXIO; /* set MODULENAME to ENABLE */ prcm_write_4(CM_PER_CPGMAC0_CLKCTRL, 2); /* wait for IDLEST to become Func(0) */ while(prcm_read_4(CM_PER_CPGMAC0_CLKCTRL) & (3<<16)); /*set CLKTRCTRL to SW_WKUP(2) */ prcm_write_4(CM_PER_CPSW_CLKSTCTRL, 2); /* wait for 125 MHz OCP clock to become active */ while((prcm_read_4(CM_PER_CPSW_CLKSTCTRL) & (1<<4)) == 0); return(0); } static int am335x_clk_musb0_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; if (sc == NULL) return ENXIO; /* set ST_DPLL_CLKDCOLDO(9) to CLK_GATED(1) */ /* set DPLL_CLKDCOLDO_GATE_CTRL(8) to CLK_ENABLE(1)*/ prcm_write_4(CM_WKUP_CM_CLKDCOLDO_DPLL_PER, 0x300); /*set MODULEMODE to ENABLE(2) */ prcm_write_4(CM_PER_USB0_CLKCTRL, 2); /* wait for MODULEMODE to become ENABLE(2) */ while ((prcm_read_4(CM_PER_USB0_CLKCTRL) & 0x3) != 2) DELAY(10); /* wait for IDLEST to become Func(0) */ while(prcm_read_4(CM_PER_USB0_CLKCTRL) & (3<<16)) DELAY(10); return(0); } static int am335x_clk_lcdc_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; if (sc == NULL) return (ENXIO); /* * For now set frequency to 2*VGA_PIXEL_CLOCK */ am335x_clk_set_arm_disp_freq(clkdev, 25175000*2); /*set MODULEMODE to ENABLE(2) */ prcm_write_4(CM_PER_LCDC_CLKCTRL, 2); /* wait for MODULEMODE to become ENABLE(2) */ while ((prcm_read_4(CM_PER_LCDC_CLKCTRL) & 0x3) != 2) DELAY(10); /* wait for IDLEST to become Func(0) */ while(prcm_read_4(CM_PER_LCDC_CLKCTRL) & (3<<16)) DELAY(10); return (0); } static int am335x_clk_pruss_activate(struct ti_clock_dev *clkdev) { struct am335x_prcm_softc *sc = am335x_prcm_sc; if (sc == NULL) return (ENXIO); /* Set MODULEMODE to ENABLE(2) */ prcm_write_4(CM_PER_PRUSS_CLKCTRL, 2); /* Wait for MODULEMODE to become ENABLE(2) */ while ((prcm_read_4(CM_PER_PRUSS_CLKCTRL) & 0x3) != 2) DELAY(10); /* Set CLKTRCTRL to SW_WKUP(2) */ prcm_write_4(CM_PER_PRUSS_CLKSTCTRL, 2); /* Wait for the 200 MHz OCP clock to become active */ while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<4)) == 0) DELAY(10); /* Wait for the 200 MHz IEP clock to become active */ while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<5)) == 0) DELAY(10); /* Wait for the 192 MHz UART clock to become active */ while ((prcm_read_4(CM_PER_PRUSS_CLKSTCTRL) & (1<<6)) == 0) DELAY(10); /* Select L3F as OCP clock */ prcm_write_4(CLKSEL_PRUSS_OCP_CLK, 0); while ((prcm_read_4(CLKSEL_PRUSS_OCP_CLK) & 0x3) != 0) DELAY(10); /* Clear the RESET bit */ prcm_write_4(PRM_PER_RSTCTRL, prcm_read_4(PRM_PER_RSTCTRL) & ~2); return (0); } Index: head/sys/arm/ti/files.ti =================================================================== --- head/sys/arm/ti/files.ti (revision 297394) +++ head/sys/arm/ti/files.ti (revision 297395) @@ -1,24 +1,25 @@ #$FreeBSD$ kern/kern_clocksource.c standard arm/ti/ti_common.c standard arm/ti/ti_cpuid.c standard arm/ti/ti_hwmods.c standard arm/ti/ti_machdep.c standard arm/ti/ti_prcm.c standard arm/ti/ti_scm.c standard arm/ti/ti_pinmux.c standard dev/mbox/mbox_if.m optional ti_mbox arm/ti/ti_mbox.c optional ti_mbox arm/ti/ti_pruss.c optional ti_pruss arm/ti/ti_wdt.c optional ti_wdt arm/ti/ti_adc.c optional ti_adc arm/ti/ti_gpio.c optional gpio arm/ti/ti_gpio_if.m optional gpio arm/ti/ti_i2c.c optional ti_i2c arm/ti/ti_sdhci.c optional sdhci +arm/ti/ti_spi.c optional ti_spi dev/uart/uart_dev_ti8250.c optional uart dev/uart/uart_dev_ns8250.c optional uart Index: head/sys/arm/ti/ti_hwmods.c =================================================================== --- head/sys/arm/ti/ti_hwmods.c (revision 297394) +++ head/sys/arm/ti/ti_hwmods.c (revision 297395) @@ -1,202 +1,205 @@ /*- * Copyright (c) 2015 Oleksandr Tymoshenko * 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. * * $FreeBSD$ */ #include __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include #include struct hwmod { const char *name; int clock_id; }; struct hwmod ti_hwmods[] = { {"i2c1", I2C1_CLK}, {"i2c2", I2C2_CLK}, {"i2c3", I2C3_CLK}, {"i2c4", I2C4_CLK}, {"i2c5", I2C5_CLK}, {"gpio1", GPIO1_CLK}, {"gpio2", GPIO2_CLK}, {"gpio3", GPIO3_CLK}, {"gpio4", GPIO4_CLK}, {"gpio5", GPIO5_CLK}, {"gpio6", GPIO6_CLK}, {"gpio7", GPIO7_CLK}, {"mmc1", MMC1_CLK}, {"mmc2", MMC2_CLK}, {"mmc3", MMC3_CLK}, {"mmc4", MMC4_CLK}, {"mmc5", MMC5_CLK}, {"mmc6", MMC6_CLK}, {"epwmss0", PWMSS0_CLK}, {"epwmss1", PWMSS1_CLK}, {"epwmss2", PWMSS2_CLK}, + {"spi0", SPI0_CLK}, + {"spi1", SPI1_CLK}, + {"timer1", TIMER1_CLK}, {"timer2", TIMER2_CLK}, {"timer3", TIMER3_CLK}, {"timer4", TIMER4_CLK}, {"timer5", TIMER5_CLK}, {"timer6", TIMER6_CLK}, {"timer7", TIMER7_CLK}, {"uart1", UART1_CLK}, {"uart2", UART2_CLK}, {"uart3", UART3_CLK}, {"uart4", UART4_CLK}, {"uart5", UART5_CLK}, {"uart6", UART6_CLK}, {"uart7", UART7_CLK}, {NULL, 0} }; clk_ident_t ti_hwmods_get_clock(device_t dev) { phandle_t node; int len, l; char *name; char *buf; int clk; struct hwmod *hw; if ((node = ofw_bus_get_node(dev)) == 0) return (INVALID_CLK_IDENT); if ((len = OF_getprop_alloc(node, "ti,hwmods", 1, (void**)&name)) <= 0) return (INVALID_CLK_IDENT); buf = name; clk = INVALID_CLK_IDENT; while ((len > 0) && (clk == INVALID_CLK_IDENT)) { for (hw = ti_hwmods; hw->name != NULL; ++hw) { if (strcmp(hw->name, name) == 0) { clk = hw->clock_id; break; } } /* Slide to the next sub-string. */ l = strlen(name) + 1; name += l; len -= l; } if (len > 0) device_printf(dev, "WARNING: more than one ti,hwmod \n"); free(buf, M_OFWPROP); return (clk); } int ti_hwmods_contains(device_t dev, const char *hwmod) { phandle_t node; int len, l; char *name; char *buf; int result; if ((node = ofw_bus_get_node(dev)) == 0) return (0); if ((len = OF_getprop_alloc(node, "ti,hwmods", 1, (void**)&name)) <= 0) return (0); buf = name; result = 0; while (len > 0) { if (strcmp(name, hwmod) == 0) { result = 1; break; } /* Slide to the next sub-string. */ l = strlen(name) + 1; name += l; len -= l; } free(buf, M_OFWPROP); return (result); } int ti_hwmods_get_unit(device_t dev, const char *hwmod) { phandle_t node; int l, len, hwmodlen, result; char *name; char *buf; if ((node = ofw_bus_get_node(dev)) == 0) return (0); if ((len = OF_getprop_alloc(node, "ti,hwmods", 1, (void**)&name)) <= 0) return (0); buf = name; hwmodlen = strlen(hwmod); result = 0; while (len > 0) { if (strncmp(name, hwmod, hwmodlen) == 0) { result = (int)strtoul(name + hwmodlen, NULL, 10); break; } /* Slide to the next sub-string. */ l = strlen(name) + 1; name += l; len -= l; } free(buf, M_OFWPROP); return (result); } Index: head/sys/arm/ti/ti_prcm.h =================================================================== --- head/sys/arm/ti/ti_prcm.h (revision 297394) +++ head/sys/arm/ti/ti_prcm.h (revision 297395) @@ -1,203 +1,207 @@ /* * Copyright (c) 2010 * Ben Gray . * 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. * * $FreeBSD$ */ /* * Texas Instruments - OMAP3xxx series processors * * Reference: * OMAP35x Applications Processor * Technical Reference Manual * (omap35xx_techref.pdf) */ #ifndef _TI_PRCM_H_ #define _TI_PRCM_H_ typedef enum { INVALID_CLK_IDENT = 0, /* System clocks, typically you can only call ti_prcm_clk_get_source_freq() * on these clocks as they are enabled by default. */ SYS_CLK = 1, /* The MPU (ARM) core clock */ MPU_CLK = 20, /* MMC modules */ MMC1_CLK = 100, MMC2_CLK, MMC3_CLK, MMC4_CLK, MMC5_CLK, MMC6_CLK, /* I2C modules */ I2C1_CLK = 200, I2C2_CLK, I2C3_CLK, I2C4_CLK, I2C5_CLK, /* USB module(s) */ USBTLL_CLK = 300, USBHSHOST_CLK, USBFSHOST_CLK, USBP1_PHY_CLK, USBP2_PHY_CLK, USBP1_UTMI_CLK, USBP2_UTMI_CLK, USBP1_HSIC_CLK, USBP2_HSIC_CLK, /* UART modules */ UART1_CLK = 400, UART2_CLK, UART3_CLK, UART4_CLK, UART5_CLK, UART6_CLK, UART7_CLK, UART8_CLK, UART9_CLK, /* General purpose timer modules */ TIMER1_CLK = 500, TIMER2_CLK, TIMER3_CLK, TIMER4_CLK, TIMER5_CLK, TIMER6_CLK, TIMER7_CLK, TIMER8_CLK, TIMER9_CLK, TIMER10_CLK, TIMER11_CLK, TIMER12_CLK, /* McBSP module(s) */ MCBSP1_CLK = 600, MCBSP2_CLK, MCBSP3_CLK, MCBSP4_CLK, MCBSP5_CLK, /* General purpose I/O modules */ GPIO1_CLK = 700, GPIO2_CLK, GPIO3_CLK, GPIO4_CLK, GPIO5_CLK, GPIO6_CLK, GPIO7_CLK, /* sDMA module */ SDMA_CLK = 800, /* CPSW modules */ CPSW_CLK = 1000, /* Mentor USB modules */ MUSB0_CLK = 1100, /* EDMA module */ EDMA_TPCC_CLK = 1200, EDMA_TPTC0_CLK, EDMA_TPTC1_CLK, EDMA_TPTC2_CLK, /* LCD controller module */ LCDC_CLK = 1300, /* PWM modules */ PWMSS0_CLK = 1400, PWMSS1_CLK, PWMSS2_CLK, /* Mailbox modules */ MAILBOX0_CLK = 1500, /* Spinlock modules */ SPINLOCK0_CLK = 1600, PRUSS_CLK = 1700, TSC_ADC_CLK = 1800, /* RTC module */ RTC_CLK = 1900, + + /* McSPI */ + SPI0_CLK = 2000, + SPI1_CLK, } clk_ident_t; /* * */ typedef enum { SYSCLK_CLK, /* System clock */ EXT_CLK, F32KHZ_CLK, /* 32KHz clock */ F48MHZ_CLK, /* 48MHz clock */ F64MHZ_CLK, /* 64MHz clock */ F96MHZ_CLK, /* 96MHz clock */ } clk_src_t; struct ti_clock_dev { /* The profile of the timer */ clk_ident_t id; /* A bunch of callbacks associated with the clock device */ int (*clk_activate)(struct ti_clock_dev *clkdev); int (*clk_deactivate)(struct ti_clock_dev *clkdev); int (*clk_set_source)(struct ti_clock_dev *clkdev, clk_src_t clksrc); int (*clk_accessible)(struct ti_clock_dev *clkdev); int (*clk_set_source_freq)(struct ti_clock_dev *clkdev, unsigned int freq); int (*clk_get_source_freq)(struct ti_clock_dev *clkdev, unsigned int *freq); }; int ti_prcm_clk_valid(clk_ident_t clk); int ti_prcm_clk_enable(clk_ident_t clk); int ti_prcm_clk_disable(clk_ident_t clk); int ti_prcm_clk_accessible(clk_ident_t clk); int ti_prcm_clk_disable_autoidle(clk_ident_t clk); int ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc); int ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq); int ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq); void ti_prcm_reset(void); #endif /* _TI_PRCM_H_ */ Index: head/sys/arm/ti/ti_spi.c =================================================================== --- head/sys/arm/ti/ti_spi.c (nonexistent) +++ head/sys/arm/ti/ti_spi.c (revision 297395) @@ -0,0 +1,582 @@ +/*- + * Copyright (c) 2016 Rubicon Communications, LLC (Netgate) + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include +#include +#include +#include + +#include "spibus_if.h" + +static void ti_spi_intr(void *); +static int ti_spi_detach(device_t); + +#undef TI_SPI_DEBUG +#ifdef TI_SPI_DEBUG +#define IRQSTATUSBITS \ + "\020\1TX0_EMPTY\2TX0_UNDERFLOW\3RX0_FULL\4RX0_OVERFLOW" \ + "\5TX1_EMPTY\6TX1_UNDERFLOW\7RX1_FULL\11TX2_EMPTY" \ + "\12TX1_UNDERFLOW\13RX2_FULL\15TX3_EMPTY\16TX3_UNDERFLOW" \ + "\17RX3_FULL\22EOW" +#define CONFBITS \ + "\020\1PHA\2POL\7EPOL\17DMAW\20DMAR\21DPE0\22DPE1\23IS" \ + "\24TURBO\25FORCE\30SBE\31SBPOL\34FFEW\35FFER\36CLKG" +#define STATBITS \ + "\020\1RXS\2TXS\3EOT\4TXFFE\5TXFFF\6RXFFE\7RXFFFF" +#define MODULCTRLBITS \ + "\020\1SINGLE\2NOSPIEN\3SLAVE\4SYST\10MOA\11FDAA" +#define CTRLBITS \ + "\020\1ENABLED" + +static void +ti_spi_printr(device_t dev) +{ + int clk, conf, ctrl, div, i, j, wl; + struct ti_spi_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + reg = TI_SPI_READ(sc, MCSPI_SYSCONFIG); + device_printf(dev, "SYSCONFIG: %#x\n", reg); + reg = TI_SPI_READ(sc, MCSPI_SYSSTATUS); + device_printf(dev, "SYSSTATUS: %#x\n", reg); + reg = TI_SPI_READ(sc, MCSPI_IRQSTATUS); + device_printf(dev, "IRQSTATUS: 0x%b\n", reg, IRQSTATUSBITS); + reg = TI_SPI_READ(sc, MCSPI_IRQENABLE); + device_printf(dev, "IRQENABLE: 0x%b\n", reg, IRQSTATUSBITS); + reg = TI_SPI_READ(sc, MCSPI_MODULCTRL); + device_printf(dev, "MODULCTRL: 0x%b\n", reg, MODULCTRLBITS); + for (i = 0; i < sc->sc_numcs; i++) { + ctrl = TI_SPI_READ(sc, MCSPI_CTRL_CH(i)); + conf = TI_SPI_READ(sc, MCSPI_CONF_CH(i)); + device_printf(dev, "CH%dCONF: 0x%b\n", i, conf, CONFBITS); + if (conf & MCSPI_CONF_CLKG) { + div = (conf >> MCSPI_CONF_CLK_SHIFT) & MCSPI_CONF_CLK_MSK; + div |= ((ctrl >> MCSPI_CTRL_EXTCLK_SHIFT) & MCSPI_CTRL_EXTCLK_MSK) << 4; + } else { + div = 1; + j = (conf >> MCSPI_CONF_CLK_SHIFT) & MCSPI_CONF_CLK_MSK; + while (j-- > 0) + div <<= 1; + } + clk = TI_SPI_GCLK / div; + wl = ((conf >> MCSPI_CONF_WL_SHIFT) & MCSPI_CONF_WL_MSK) + 1; + device_printf(dev, "wordlen: %-2d clock: %d\n", wl, clk); + reg = TI_SPI_READ(sc, MCSPI_STAT_CH(i)); + device_printf(dev, "CH%dSTAT: 0x%b\n", i, reg, STATBITS); + device_printf(dev, "CH%dCTRL: 0x%b\n", i, ctrl, CTRLBITS); + } + reg = TI_SPI_READ(sc, MCSPI_XFERLEVEL); + device_printf(dev, "XFERLEVEL: %#x\n", reg); +} +#endif + +static void +ti_spi_set_clock(struct ti_spi_softc *sc, int ch, int freq) +{ + uint32_t clkdiv, conf, div, extclk, reg; + + clkdiv = TI_SPI_GCLK / freq; + if (clkdiv > MCSPI_EXTCLK_MSK) { + extclk = 0; + clkdiv = 0; + div = 1; + while (TI_SPI_GCLK / div > freq && clkdiv <= 0xf) { + clkdiv++; + div <<= 1; + } + conf = clkdiv << MCSPI_CONF_CLK_SHIFT; + } else { + extclk = clkdiv >> 4; + clkdiv &= MCSPI_CONF_CLK_MSK; + conf = MCSPI_CONF_CLKG | clkdiv << MCSPI_CONF_CLK_SHIFT; + } + + reg = TI_SPI_READ(sc, MCSPI_CTRL_CH(ch)); + reg &= ~(MCSPI_CTRL_EXTCLK_MSK << MCSPI_CTRL_EXTCLK_SHIFT); + reg |= extclk << MCSPI_CTRL_EXTCLK_SHIFT; + TI_SPI_WRITE(sc, MCSPI_CTRL_CH(ch), reg); + + reg = TI_SPI_READ(sc, MCSPI_CONF_CH(ch)); + reg &= ~(MCSPI_CONF_CLKG | MCSPI_CONF_CLK_MSK << MCSPI_CONF_CLK_SHIFT); + TI_SPI_WRITE(sc, MCSPI_CONF_CH(ch), reg | conf); +} + +static int +ti_spi_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + if (!ofw_bus_is_compatible(dev, "ti,omap4-mcspi")) + return (ENXIO); + + device_set_desc(dev, "TI McSPI controller"); + + return (BUS_PROBE_DEFAULT); +} + +static int +ti_spi_attach(device_t dev) +{ + int clk_id, err, i, rid, timeout; + struct ti_spi_softc *sc; + uint32_t rev; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + + /* + * Get the MMCHS device id from FDT. If it's not there use the newbus + * unit number (which will work as long as the devices are in order and + * none are skipped in the fdt). Note that this is a property we made + * up and added in freebsd, it doesn't exist in the published bindings. + */ + clk_id = ti_hwmods_get_clock(dev); + if (clk_id == INVALID_CLK_IDENT) { + device_printf(dev, + "failed to get clock based on hwmods property\n"); + return (EINVAL); + } + + /* Activate the McSPI module. */ + err = ti_prcm_clk_enable(clk_id); + if (err) { + device_printf(dev, "Error: failed to activate source clock\n"); + return (err); + } + + /* Get the number of available channels. */ + if ((OF_getencprop(ofw_bus_get_node(dev), "ti,spi-num-cs", + &sc->sc_numcs, sizeof(sc->sc_numcs))) <= 0) { + sc->sc_numcs = 2; + } + + rid = 0; + sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (!sc->sc_mem_res) { + device_printf(dev, "cannot allocate memory window\n"); + return (ENXIO); + } + + sc->sc_bst = rman_get_bustag(sc->sc_mem_res); + sc->sc_bsh = rman_get_bushandle(sc->sc_mem_res); + + rid = 0; + sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (!sc->sc_irq_res) { + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); + device_printf(dev, "cannot allocate interrupt\n"); + return (ENXIO); + } + + /* Hook up our interrupt handler. */ + if (bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_MISC | INTR_MPSAFE, + NULL, ti_spi_intr, sc, &sc->sc_intrhand)) { + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); + device_printf(dev, "cannot setup the interrupt handler\n"); + return (ENXIO); + } + + mtx_init(&sc->sc_mtx, "ti_spi", NULL, MTX_DEF); + + /* Issue a softreset to the controller */ + TI_SPI_WRITE(sc, MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET); + timeout = 1000; + while (!(TI_SPI_READ(sc, MCSPI_SYSSTATUS) & + MCSPI_SYSSTATUS_RESETDONE)) { + if (--timeout == 0) { + device_printf(dev, + "Error: Controller reset operation timed out\n"); + ti_spi_detach(dev); + return (ENXIO); + } + DELAY(100); + } + + /* Print the McSPI module revision. */ + rev = TI_SPI_READ(sc, MCSPI_REVISION); + device_printf(dev, + "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n", + (rev >> MCSPI_REVISION_SCHEME_SHIFT) & MCSPI_REVISION_SCHEME_MSK, + (rev >> MCSPI_REVISION_FUNC_SHIFT) & MCSPI_REVISION_FUNC_MSK, + (rev >> MCSPI_REVISION_RTL_SHIFT) & MCSPI_REVISION_RTL_MSK, + (rev >> MCSPI_REVISION_MAJOR_SHIFT) & MCSPI_REVISION_MAJOR_MSK, + (rev >> MCSPI_REVISION_MINOR_SHIFT) & MCSPI_REVISION_MINOR_MSK, + (rev >> MCSPI_REVISION_CUSTOM_SHIFT) & MCSPI_REVISION_CUSTOM_MSK); + + /* Set Master mode, single channel. */ + TI_SPI_WRITE(sc, MCSPI_MODULCTRL, MCSPI_MODULCTRL_SINGLE); + + /* Clear pending interrupts and disable interrupts. */ + TI_SPI_WRITE(sc, MCSPI_IRQENABLE, 0x0); + TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, 0xffff); + + for (i = 0; i < sc->sc_numcs; i++) { + /* + * Default to SPI mode 0, CS active low, 8 bits word length and + * 500kHz clock. + */ + TI_SPI_WRITE(sc, MCSPI_CONF_CH(i), + MCSPI_CONF_DPE0 | MCSPI_CONF_EPOL | + (8 - 1) << MCSPI_CONF_WL_SHIFT); + /* Set initial clock - 500kHz. */ + ti_spi_set_clock(sc, i, 500000); + } + +#ifdef TI_SPI_DEBUG + ti_spi_printr(dev); +#endif + + device_add_child(dev, "spibus", -1); + + return (bus_generic_attach(dev)); +} + +static int +ti_spi_detach(device_t dev) +{ + struct ti_spi_softc *sc; + + sc = device_get_softc(dev); + + /* Clear pending interrupts and disable interrupts. */ + TI_SPI_WRITE(sc, MCSPI_IRQENABLE, 0); + TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, 0xffff); + + /* Reset controller. */ + TI_SPI_WRITE(sc, MCSPI_SYSCONFIG, MCSPI_SYSCONFIG_SOFTRESET); + + bus_generic_detach(dev); + + mtx_destroy(&sc->sc_mtx); + if (sc->sc_intrhand) + bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intrhand); + if (sc->sc_irq_res) + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); + if (sc->sc_mem_res) + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_mem_res); + + return (0); +} + +static int +ti_spi_fill_fifo(struct ti_spi_softc *sc) +{ + int bytes, timeout; + struct spi_command *cmd; + uint32_t written; + uint8_t *data; + + cmd = sc->sc_cmd; + bytes = min(sc->sc_len - sc->sc_written, sc->sc_fifolvl); + while (bytes-- > 0) { + data = (uint8_t *)cmd->tx_cmd; + written = sc->sc_written++; + if (written >= cmd->tx_cmd_sz) { + data = (uint8_t *)cmd->tx_data; + written -= cmd->tx_cmd_sz; + } + if (sc->sc_fifolvl == 1) { + /* FIFO disabled. */ + timeout = 1000; + while (--timeout > 0 && (TI_SPI_READ(sc, + MCSPI_STAT_CH(sc->sc_cs)) & MCSPI_STAT_TXS) == 0) { + DELAY(1); + } + if (timeout == 0) + return (-1); + } + TI_SPI_WRITE(sc, MCSPI_TX_CH(sc->sc_cs), data[written]); + } + + return (0); +} + +static int +ti_spi_drain_fifo(struct ti_spi_softc *sc) +{ + int bytes, timeout; + struct spi_command *cmd; + uint32_t read; + uint8_t *data; + + cmd = sc->sc_cmd; + bytes = min(sc->sc_len - sc->sc_read, sc->sc_fifolvl); + while (bytes-- > 0) { + data = (uint8_t *)cmd->rx_cmd; + read = sc->sc_read++; + if (read >= cmd->rx_cmd_sz) { + data = (uint8_t *)cmd->rx_data; + read -= cmd->rx_cmd_sz; + } + if (sc->sc_fifolvl == 1) { + /* FIFO disabled. */ + timeout = 1000; + while (--timeout > 0 && (TI_SPI_READ(sc, + MCSPI_STAT_CH(sc->sc_cs)) & MCSPI_STAT_RXS) == 0) { + DELAY(1); + } + if (timeout == 0) + return (-1); + } + data[read] = TI_SPI_READ(sc, MCSPI_RX_CH(sc->sc_cs)); + } + + return (0); +} + +static void +ti_spi_intr(void *arg) +{ + int eow; + struct ti_spi_softc *sc; + uint32_t status; + + eow = 0; + sc = (struct ti_spi_softc *)arg; + TI_SPI_LOCK(sc); + status = TI_SPI_READ(sc, MCSPI_IRQSTATUS); + + /* + * No new TX_empty or RX_full event will be asserted while the CPU has + * not performed the number of writes or reads defined by + * MCSPI_XFERLEVEL[AEL] and MCSPI_XFERLEVEL[AFL]. It is responsibility + * of CPU perform the right number of writes and reads. + */ + if (status & MCSPI_IRQ_TX0_EMPTY) + ti_spi_fill_fifo(sc); + if (status & MCSPI_IRQ_RX0_FULL) + ti_spi_drain_fifo(sc); + + if (status & MCSPI_IRQ_EOW) + eow = 1; + + /* Clear interrupt status. */ + TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, status); + + /* Check for end of transfer. */ + if (sc->sc_written == sc->sc_len && sc->sc_read == sc->sc_len) { + sc->sc_flags |= TI_SPI_DONE; + wakeup(sc->sc_dev); + } + + TI_SPI_UNLOCK(sc); +} + +static int +ti_spi_pio_transfer(struct ti_spi_softc *sc) +{ + + while (sc->sc_len - sc->sc_written > 0) { + if (ti_spi_fill_fifo(sc) == -1) + return (EIO); + if (ti_spi_drain_fifo(sc) == -1) + return (EIO); + } + + return (0); +} + +static int +ti_spi_gcd(int a, int b) +{ + int m; + + while ((m = a % b) != 0) { + a = b; + b = m; + } + + return (b); +} + +static int +ti_spi_transfer(device_t dev, device_t child, struct spi_command *cmd) +{ + int cs, err; + struct ti_spi_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + + KASSERT(cmd->tx_cmd_sz == cmd->rx_cmd_sz, + ("TX/RX command sizes should be equal")); + KASSERT(cmd->tx_data_sz == cmd->rx_data_sz, + ("TX/RX data sizes should be equal")); + + /* Get the proper chip select for this child. */ + spibus_get_cs(child, &cs); + if (cs < 0 || cs > sc->sc_numcs) { + device_printf(dev, "Invalid chip select %d requested by %s\n", + cs, device_get_nameunit(child)); + return (EINVAL); + } + + TI_SPI_LOCK(sc); + + /* If the controller is in use wait until it is available. */ + while (sc->sc_flags & TI_SPI_BUSY) + mtx_sleep(dev, &sc->sc_mtx, 0, "ti_spi", 0); + + /* Now we have control over SPI controller. */ + sc->sc_flags = TI_SPI_BUSY; + + /* Save the SPI command data. */ + sc->sc_cs = cs; + sc->sc_cmd = cmd; + sc->sc_read = 0; + sc->sc_written = 0; + sc->sc_len = cmd->tx_cmd_sz + cmd->tx_data_sz; + sc->sc_fifolvl = ti_spi_gcd(sc->sc_len, TI_SPI_FIFOSZ); + if (sc->sc_fifolvl < 2 || sc->sc_len > 0xffff) + sc->sc_fifolvl = 1; /* FIFO disabled. */ + /* Disable FIFO for now. */ + sc->sc_fifolvl = 1; + + /* Use a safe clock - 500kHz. */ + ti_spi_set_clock(sc, sc->sc_cs, 500000); + + /* Disable the FIFO. */ + TI_SPI_WRITE(sc, MCSPI_XFERLEVEL, 0); + + /* 8 bits word, d0 miso, d1 mosi, mode 0 and CS active low. */ + reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs)); + reg &= ~(MCSPI_CONF_FFER | MCSPI_CONF_FFEW | MCSPI_CONF_SBPOL | + MCSPI_CONF_SBE | MCSPI_CONF_TURBO | MCSPI_CONF_IS | + MCSPI_CONF_DPE1 | MCSPI_CONF_DPE0 | MCSPI_CONF_DMAR | + MCSPI_CONF_DMAW | MCSPI_CONF_EPOL); + reg |= MCSPI_CONF_DPE0 | MCSPI_CONF_EPOL | MCSPI_CONF_WL8BITS; + TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg); + +#if 0 + /* Enable channel interrupts. */ + reg = TI_SPI_READ(sc, MCSPI_IRQENABLE); + reg |= 0xf; + TI_SPI_WRITE(sc, MCSPI_IRQENABLE, reg); +#endif + + /* Start the transfer. */ + reg = TI_SPI_READ(sc, MCSPI_CTRL_CH(sc->sc_cs)); + TI_SPI_WRITE(sc, MCSPI_CTRL_CH(sc->sc_cs), reg | MCSPI_CTRL_ENABLE); + + /* Force CS on. */ + reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs)); + TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg |= MCSPI_CONF_FORCE); + + err = 0; + if (sc->sc_fifolvl == 1) + err = ti_spi_pio_transfer(sc); + + /* Force CS off. */ + reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs)); + reg &= ~MCSPI_CONF_FORCE; + TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg); + + /* Disable IRQs. */ + reg = TI_SPI_READ(sc, MCSPI_IRQENABLE); + reg &= ~0xf; + TI_SPI_WRITE(sc, MCSPI_IRQENABLE, reg); + TI_SPI_WRITE(sc, MCSPI_IRQSTATUS, 0xf); + + /* Disable the SPI channel. */ + reg = TI_SPI_READ(sc, MCSPI_CTRL_CH(sc->sc_cs)); + reg &= ~MCSPI_CTRL_ENABLE; + TI_SPI_WRITE(sc, MCSPI_CTRL_CH(sc->sc_cs), reg); + + /* Disable FIFO. */ + reg = TI_SPI_READ(sc, MCSPI_CONF_CH(sc->sc_cs)); + reg &= ~(MCSPI_CONF_FFER | MCSPI_CONF_FFEW); + TI_SPI_WRITE(sc, MCSPI_CONF_CH(sc->sc_cs), reg); + + /* Release the controller and wakeup the next thread waiting for it. */ + sc->sc_flags = 0; + wakeup_one(dev); + TI_SPI_UNLOCK(sc); + + return (err); +} + +static phandle_t +ti_spi_get_node(device_t bus, device_t dev) +{ + + /* Share controller node with spibus. */ + return (ofw_bus_get_node(bus)); +} + +static device_method_t ti_spi_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_spi_probe), + DEVMETHOD(device_attach, ti_spi_attach), + DEVMETHOD(device_detach, ti_spi_detach), + + /* SPI interface */ + DEVMETHOD(spibus_transfer, ti_spi_transfer), + + /* ofw_bus interface */ + DEVMETHOD(ofw_bus_get_node, ti_spi_get_node), + + DEVMETHOD_END +}; + +static devclass_t ti_spi_devclass; + +static driver_t ti_spi_driver = { + "spi", + ti_spi_methods, + sizeof(struct ti_spi_softc), +}; + +DRIVER_MODULE(ti_spi, simplebus, ti_spi_driver, ti_spi_devclass, 0, 0); Property changes on: head/sys/arm/ti/ti_spi.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/ti_spireg.h =================================================================== --- head/sys/arm/ti/ti_spireg.h (nonexistent) +++ head/sys/arm/ti/ti_spireg.h (revision 297395) @@ -0,0 +1,97 @@ +/*- + * Copyright (c) 2016 Rubicon Communications, LLC (Netgate) + * 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 _TI_SPIREG_H_ +#define _TI_SPIREG_H_ + +#define TI_SPI_GCLK 48000000U +#define TI_SPI_FIFOSZ 32 +#define MCSPI_REVISION 0x0 +#define MCSPI_REVISION_SCHEME_SHIFT 30 +#define MCSPI_REVISION_SCHEME_MSK 0x3 +#define MCSPI_REVISION_FUNC_SHIFT 16 +#define MCSPI_REVISION_FUNC_MSK 0xfff +#define MCSPI_REVISION_RTL_SHIFT 11 +#define MCSPI_REVISION_RTL_MSK 0x1f +#define MCSPI_REVISION_MAJOR_SHIFT 8 +#define MCSPI_REVISION_MAJOR_MSK 0x7 +#define MCSPI_REVISION_CUSTOM_SHIFT 6 +#define MCSPI_REVISION_CUSTOM_MSK 0x3 +#define MCSPI_REVISION_MINOR_SHIFT 0 +#define MCSPI_REVISION_MINOR_MSK 0x3f +#define MCSPI_SYSCONFIG 0x110 +#define MCSPI_SYSCONFIG_SOFTRESET (1 << 1) +#define MCSPI_SYSSTATUS 0x114 +#define MCSPI_SYSSTATUS_RESETDONE (1 << 0) +#define MCSPI_MODULCTRL 0x128 +#define MCSPI_MODULCTRL_SLAVE (1 << 2) +#define MCSPI_MODULCTRL_SINGLE (1 << 0) +#define MCSPI_IRQSTATUS 0x118 +#define MCSPI_IRQENABLE 0x11c +#define MCSPI_IRQ_EOW (1 << 17) +#define MCSPI_IRQ_RX0_OVERFLOW (1 << 3) +#define MCSPI_IRQ_RX0_FULL (1 << 2) +#define MCSPI_IRQ_TX0_UNDERFLOW (1 << 1) +#define MCSPI_IRQ_TX0_EMPTY (1 << 0) +#define MCSPI_CONF_CH(_c) (0x12c + 0x14 * (_c)) +#define MCSPI_CONF_CLKG (1 << 29) +#define MCSPI_CONF_FFER (1 << 28) +#define MCSPI_CONF_FFEW (1 << 27) +#define MCSPI_CONF_SBPOL (1 << 24) +#define MCSPI_CONF_SBE (1 << 23) +#define MCSPI_CONF_FORCE (1 << 20) +#define MCSPI_CONF_TURBO (1 << 19) +#define MCSPI_CONF_IS (1 << 18) +#define MCSPI_CONF_DPE1 (1 << 17) +#define MCSPI_CONF_DPE0 (1 << 16) +#define MCSPI_CONF_DMAR (1 << 15) +#define MCSPI_CONF_DMAW (1 << 14) +#define MCSPI_CONF_WL_MSK 0x1f +#define MCSPI_CONF_WL_SHIFT 7 +#define MCSPI_CONF_WL8BITS (7 << MCSPI_CONF_WL_SHIFT) +#define MCSPI_CONF_EPOL (1 << 6) +#define MCSPI_CONF_CLK_MSK 0xf +#define MCSPI_CONF_CLK_SHIFT 2 +#define MCSPI_CONF_POL (1 << 1) +#define MCSPI_CONF_PHA (1 << 0) +#define MCSPI_STAT_CH(_c) (0x130 + 0x14 * (_c)) +#define MCSPI_STAT_TXFFF (1 << 4) +#define MCSPI_STAT_TXS (1 << 1) +#define MCSPI_STAT_RXS (1 << 0) +#define MCSPI_CTRL_CH(_c) (0x134 + 0x14 * (_c)) +#define MCSPI_EXTCLK_MSK 0xfff +#define MCSPI_CTRL_EXTCLK_MSK 0xff +#define MCSPI_CTRL_EXTCLK_SHIFT 8 +#define MCSPI_CTRL_ENABLE (1 << 0) +#define MCSPI_TX_CH(_c) (0x138 + 0x14 * (_c)) +#define MCSPI_RX_CH(_c) (0x13c + 0x14 * (_c)) +#define MCSPI_XFERLEVEL 0x17c +#define MCSPI_XFERLEVEL_AFL(_a) (((_a) >> 8) & 0xff) +#define MCSPI_XFERLEVEL_AEL(_a) (((_a) >> 0) & 0xff) + +#endif /* _TI_SPIREG_H_ */ Property changes on: head/sys/arm/ti/ti_spireg.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: head/sys/arm/ti/ti_spivar.h =================================================================== --- head/sys/arm/ti/ti_spivar.h (nonexistent) +++ head/sys/arm/ti/ti_spivar.h (revision 297395) @@ -0,0 +1,71 @@ +/*- + * Copyright (c) 2016 Rubicon Communications, LLC (Netgate) + * 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 _TI_SPIVAR_H_ +#define _TI_SPIVAR_H_ + +struct ti_spi_softc { + bus_space_tag_t sc_bst; + bus_space_handle_t sc_bsh; + device_t sc_dev; + int sc_numcs; + struct mtx sc_mtx; + struct resource *sc_mem_res; + struct resource *sc_irq_res; + struct { + int cs; + int fifolvl; + struct spi_command *cmd; + uint32_t len; + uint32_t read; + uint32_t written; + } xfer; + uint32_t sc_flags; + void *sc_intrhand; +#define sc_cs xfer.cs +#define sc_fifolvl xfer.fifolvl +#define sc_cmd xfer.cmd +#define sc_len xfer.len +#define sc_read xfer.read +#define sc_written xfer.written +}; + +#define TI_SPI_BUSY 0x1 +#define TI_SPI_DONE 0x2 + +#define TI_SPI_WRITE(_sc, _off, _val) \ + bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off), (_val)) +#define TI_SPI_READ(_sc, _off) \ + bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, (_off)) + +#define TI_SPI_LOCK(_sc) \ + mtx_lock(&(_sc)->sc_mtx) +#define TI_SPI_UNLOCK(_sc) \ + mtx_unlock(&(_sc)->sc_mtx) + +#endif /* _TI_SPIVAR_H_ */ Property changes on: head/sys/arm/ti/ti_spivar.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property