Index: head/sys/arm/ti/am335x/am3359_cppi41.c =================================================================== --- head/sys/arm/ti/am335x/am3359_cppi41.c +++ head/sys/arm/ti/am335x/am3359_cppi41.c @@ -0,0 +1,192 @@ +/*- + * Copyright (c) 2019 Emmanuel Vadot + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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$ + */ +/* Based on sys/arm/ti/ti_sysc.c */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +struct ti_am3359_cppi41_softc { + device_t dev; + struct syscon * syscon; + struct resource * res[4]; + bus_space_tag_t bst; + bus_space_handle_t bsh; + struct mtx mtx; +}; + +static struct resource_spec ti_am3359_cppi41_res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE }, + { SYS_RES_MEMORY, 1, RF_ACTIVE | RF_SHAREABLE }, + { SYS_RES_MEMORY, 2, RF_ACTIVE | RF_SHAREABLE }, + { SYS_RES_MEMORY, 3, RF_ACTIVE | RF_SHAREABLE }, + { -1, 0 } +}; + +/* Device */ +static struct ofw_compat_data compat_data[] = { + { "ti,am3359-cppi41", 1 }, + { NULL, 0 } +}; + +static int +ti_am3359_cppi41_write_4(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct ti_am3359_cppi41_softc *sc; + + sc = device_get_softc(dev); + DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val); + mtx_lock(&sc->mtx); + bus_space_write_4(sc->bst, sc->bsh, addr, val); + mtx_unlock(&sc->mtx); + return (0); +} + +static uint32_t +ti_am3359_cppi41_read_4(device_t dev, bus_addr_t addr) +{ + struct ti_am3359_cppi41_softc *sc; + uint32_t val; + + sc = device_get_softc(dev); + + mtx_lock(&sc->mtx); + val = bus_space_read_4(sc->bst, sc->bsh, addr); + mtx_unlock(&sc->mtx); + DPRINTF(sc->dev, "offset=%lx Read %x\n", addr, val); + return (val); +} + +/* device interface */ +static int +ti_am3359_cppi41_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI AM3359 CPPI 41"); + return(BUS_PROBE_DEFAULT); +} + +static int +ti_am3359_cppi41_attach(device_t dev) +{ + struct ti_am3359_cppi41_softc *sc; + phandle_t node; + uint32_t reg, reset_bit, timeout=10; + uint64_t sysc_address; + device_t parent; + + sc = device_get_softc(dev); + sc->dev = dev; + + if (bus_alloc_resources(dev, ti_am3359_cppi41_res_spec, sc->res)) { + device_printf(sc->dev, "Cant allocate resources\n"); + return (ENXIO); + } + + sc->dev = dev; + sc->bst = rman_get_bustag(sc->res[0]); + sc->bsh = rman_get_bushandle(sc->res[0]); + + mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF); + node = ofw_bus_get_node(sc->dev); + + /* variant of am335x_usbss.c */ + DPRINTF(dev, "-- RESET USB --\n"); + parent = device_get_parent(dev); + reset_bit = ti_sysc_get_soft_reset_bit(parent); + if (reset_bit == 0) { + DPRINTF(dev, "Dont have reset bit\n"); + return (0); + } + sysc_address = ti_sysc_get_sysc_address_offset_host(parent); + DPRINTF(dev, "sysc_address %x\n", sysc_address); + ti_am3359_cppi41_write_4(dev, sysc_address, reset_bit); + DELAY(100); + reg = ti_am3359_cppi41_read_4(dev, sysc_address); + if ((reg & reset_bit) && timeout--) { + DPRINTF(dev, "Reset still ongoing - wait a little bit longer\n"); + DELAY(100); + reg = ti_am3359_cppi41_read_4(dev, sysc_address); + } + if (timeout == 0) + device_printf(dev, "USB Reset timeout\n"); + + return (0); +} + + +static device_method_t ti_am3359_cppi41_methods[] = { + DEVMETHOD(device_probe, ti_am3359_cppi41_probe), + DEVMETHOD(device_attach, ti_am3359_cppi41_attach), + + DEVMETHOD_END +}; + + +DEFINE_CLASS_1(ti_am3359_cppi41, ti_am3359_cppi41_driver, + ti_am3359_cppi41_methods,sizeof(struct ti_am3359_cppi41_softc), + simplebus_driver); + +static devclass_t ti_am3359_cppi41_devclass; + +EARLY_DRIVER_MODULE(ti_am3359_cppi41, simplebus, ti_am3359_cppi41_driver, + ti_am3359_cppi41_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_am3359_cppi41, 1); +MODULE_DEPEND(ti_am3359_cppi41, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_dmtimer.c =================================================================== --- head/sys/arm/ti/am335x/am335x_dmtimer.c +++ head/sys/arm/ti/am335x/am335x_dmtimer.c @@ -42,12 +42,13 @@ #include /* For arm_set_delay */ +#include + #include #include #include -#include -#include +#include #include "am335x_dmtreg.h" @@ -58,7 +59,8 @@ int tmr_irq_rid; struct resource * tmr_irq_res; void *tmr_irq_handler; - uint32_t sysclk_freq; + clk_t clk_fck; + uint64_t sysclk_freq; uint32_t tclr; /* Cached TCLR register. */ union { struct timecounter tc; @@ -251,6 +253,7 @@ { char strbuf[32]; int tmr_num; + uint64_t rev_address; if (!ofw_bus_status_okay(dev)) return (ENXIO); @@ -259,13 +262,22 @@ return (ENXIO); /* - * Get the hardware unit number (the N from ti,hwmods="timerN"). + * Get the hardware unit number from address of rev register. * If this isn't the hardware unit we're going to use for either the * eventtimer or the timecounter, no point in instantiating the device. */ - tmr_num = ti_hwmods_get_unit(dev, "timer"); - if (tmr_num != ET_TMR_NUM && tmr_num != TC_TMR_NUM) - return (ENXIO); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case DMTIMER2_REV: + tmr_num = 2; + break; + case DMTIMER3_REV: + tmr_num = 3; + break; + default: + /* Not DMTIMER2 or DMTIMER3 */ + return (ENXIO); + } snprintf(strbuf, sizeof(strbuf), "AM335x DMTimer%d", tmr_num); device_set_desc_copy(dev, strbuf); @@ -277,24 +289,47 @@ am335x_dmtimer_attach(device_t dev) { struct am335x_dmtimer_softc *sc; - clk_ident_t timer_id; int err; + uint64_t rev_address; + clk_t sys_clkin; sc = device_get_softc(dev); sc->dev = dev; - /* Get the base clock frequency. */ - if ((err = ti_prcm_clk_get_source_freq(SYS_CLK, &sc->sysclk_freq)) != 0) - return (err); + /* expect one clock */ + err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk_fck); + if (err != 0) { + device_printf(dev, "Cant find clock index 0. err: %d\n", err); + return (ENXIO); + } + err = clk_get_by_name(dev, "sys_clkin_ck@40", &sys_clkin); + if (err != 0) { + device_printf(dev, "Cant find sys_clkin_ck@40 err: %d\n", err); + return (ENXIO); + } + + /* Select M_OSC as DPLL parent */ + err = clk_set_parent_by_clk(sc->clk_fck, sys_clkin); + if (err != 0) { + device_printf(dev, "Cant set mux to CLK_M_OSC\n"); + return (ENXIO); + } + /* Enable clocks and power on the device. */ - if ((timer_id = ti_hwmods_get_clock(dev)) == INVALID_CLK_IDENT) + err = ti_sysc_clock_enable(device_get_parent(dev)); + if (err != 0) { + device_printf(dev, "Cant enable sysc clkctrl, err %d\n", err); return (ENXIO); - if ((err = ti_prcm_clk_set_source(timer_id, SYSCLK_CLK)) != 0) - return (err); - if ((err = ti_prcm_clk_enable(timer_id)) != 0) - return (err); + } + /* Get the base clock frequency. */ + err = clk_get_freq(sc->clk_fck, &sc->sysclk_freq); + if (err != 0) { + device_printf(dev, "Cant get sysclk frequency, err %d\n", err); + return (ENXIO); + } + /* Request the memory resources. */ sc->tmr_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->tmr_mem_rid, RF_ACTIVE); @@ -302,7 +337,20 @@ return (ENXIO); } - sc->tmr_num = ti_hwmods_get_unit(dev, "timer"); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case DMTIMER2_REV: + sc->tmr_num = 2; + break; + case DMTIMER3_REV: + sc->tmr_num = 3; + break; + default: + device_printf(dev, "Not timer 2 or 3! %#jx\n", + rev_address); + return (ENXIO); + } + snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num); /* @@ -334,7 +382,7 @@ static devclass_t am335x_dmtimer_devclass; DRIVER_MODULE(am335x_dmtimer, simplebus, am335x_dmtimer_driver, am335x_dmtimer_devclass, 0, 0); -MODULE_DEPEND(am335x_dmtimer, am335x_prcm, 1, 1, 1); +MODULE_DEPEND(am335x_dmtimer, ti_sysc, 1, 1, 1); static void am335x_dmtimer_delay(int usec, void *arg) Index: head/sys/arm/ti/am335x/am335x_dmtpps.c =================================================================== --- head/sys/arm/ti/am335x/am335x_dmtpps.c +++ head/sys/arm/ti/am335x/am335x_dmtpps.c @@ -43,6 +43,8 @@ #include __FBSDID("$FreeBSD$"); +#include "opt_platform.h" + #include #include #include @@ -60,9 +62,9 @@ #include #include #include +#include -#include -#include +#include #include #include @@ -82,6 +84,8 @@ struct cdev * pps_cdev; struct pps_state pps_state; struct mtx pps_mtx; + clk_t clk_fck; + uint64_t sysclk_freq; }; static int dmtpps_tmr_num; /* Set by probe() */ @@ -383,6 +387,7 @@ { char strbuf[64]; int tmr_num; + uint64_t rev_address; if (!ofw_bus_status_okay(dev)) return (ENXIO); @@ -402,7 +407,33 @@ * Figure out which hardware timer is being probed and see if it matches * the configured timer number determined earlier. */ - tmr_num = ti_hwmods_get_unit(dev, "timer"); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case DMTIMER1_1MS_REV: + tmr_num = 1; + break; + case DMTIMER2_REV: + tmr_num = 2; + break; + case DMTIMER3_REV: + tmr_num = 3; + break; + case DMTIMER4_REV: + tmr_num = 4; + break; + case DMTIMER5_REV: + tmr_num = 5; + break; + case DMTIMER6_REV: + tmr_num = 6; + break; + case DMTIMER7_REV: + tmr_num = 7; + break; + default: + return (ENXIO); + } + if (dmtpps_tmr_num != tmr_num) return (ENXIO); @@ -418,23 +449,73 @@ { struct dmtpps_softc *sc; struct make_dev_args mda; - clk_ident_t timer_id; - int err, sysclk_freq; + int err; + clk_t sys_clkin; + uint64_t rev_address; sc = device_get_softc(dev); sc->dev = dev; - /* Get the base clock frequency. */ - err = ti_prcm_clk_get_source_freq(SYS_CLK, &sysclk_freq); + /* Figure out which hardware timer this is and set the name string. */ + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case DMTIMER1_1MS_REV: + sc->tmr_num = 1; + break; + case DMTIMER2_REV: + sc->tmr_num = 2; + break; + case DMTIMER3_REV: + sc->tmr_num = 3; + break; + case DMTIMER4_REV: + sc->tmr_num = 4; + break; + case DMTIMER5_REV: + sc->tmr_num = 5; + break; + case DMTIMER6_REV: + sc->tmr_num = 6; + break; + case DMTIMER7_REV: + sc->tmr_num = 7; + break; + } + snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num); + /* expect one clock */ + err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk_fck); + if (err != 0) { + device_printf(dev, "Cant find clock index 0. err: %d\n", err); + return (ENXIO); + } + + err = clk_get_by_name(dev, "sys_clkin_ck@40", &sys_clkin); + if (err != 0) { + device_printf(dev, "Cant find sys_clkin_ck@40 err: %d\n", err); + return (ENXIO); + } + + /* Select M_OSC as DPLL parent */ + err = clk_set_parent_by_clk(sc->clk_fck, sys_clkin); + if (err != 0) { + device_printf(dev, "Cant set mux to CLK_M_OSC\n"); + return (ENXIO); + } + /* Enable clocks and power on the device. */ - if ((timer_id = ti_hwmods_get_clock(dev)) == INVALID_CLK_IDENT) + err = ti_sysc_clock_enable(device_get_parent(dev)); + if (err != 0) { + device_printf(dev, "Cant enable sysc clkctrl, err %d\n", err); return (ENXIO); - if ((err = ti_prcm_clk_set_source(timer_id, SYSCLK_CLK)) != 0) - return (err); - if ((err = ti_prcm_clk_enable(timer_id)) != 0) - return (err); + } + /* Get the base clock frequency. */ + err = clk_get_freq(sc->clk_fck, &sc->sysclk_freq); + if (err != 0) { + device_printf(dev, "Cant get sysclk frequency, err %d\n", err); + return (ENXIO); + } /* Request the memory resources. */ sc->mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &sc->mem_rid, RF_ACTIVE); @@ -442,10 +523,6 @@ return (ENXIO); } - /* Figure out which hardware timer this is and set the name string. */ - sc->tmr_num = ti_hwmods_get_unit(dev, "timer"); - snprintf(sc->tmr_name, sizeof(sc->tmr_name), "DMTimer%d", sc->tmr_num); - /* * Configure the timer pulse/capture pin to input/capture mode. This is * required in addition to configuring the pin as input with the pinmux @@ -468,7 +545,7 @@ sc->tc.tc_name = sc->tmr_name; sc->tc.tc_get_timecount = dmtpps_get_timecount; sc->tc.tc_counter_mask = ~0u; - sc->tc.tc_frequency = sysclk_freq; + sc->tc.tc_frequency = sc->sysclk_freq; sc->tc.tc_quality = 1000; sc->tc.tc_priv = sc; @@ -541,5 +618,4 @@ static devclass_t dmtpps_devclass; DRIVER_MODULE(am335x_dmtpps, simplebus, dmtpps_driver, dmtpps_devclass, 0, 0); -MODULE_DEPEND(am335x_dmtpps, am335x_prcm, 1, 1, 1); - +MODULE_DEPEND(am335x_dmtpps, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_dmtreg.h =================================================================== --- head/sys/arm/ti/am335x/am335x_dmtreg.h +++ head/sys/arm/ti/am335x/am335x_dmtreg.h @@ -73,4 +73,16 @@ #define DMT_TSICR_RESET (1 << 1) /* TSICR perform soft reset */ #define DMT_TCAR2 0x48 /* Capture Reg */ +/* Location of revision register from TRM Memory map chapter 2 */ +/* L4_WKUP */ +#define DMTIMER0_REV 0x05000 +#define DMTIMER1_1MS_REV 0x31000 +/* L4_PER */ +#define DMTIMER2_REV 0x40000 +#define DMTIMER3_REV 0x42000 +#define DMTIMER4_REV 0x44000 +#define DMTIMER5_REV 0x46000 +#define DMTIMER6_REV 0x48000 +#define DMTIMER7_REV 0x4A000 + #endif /* AM335X_DMTREG_H */ Index: head/sys/arm/ti/am335x/am335x_gpio.c =================================================================== --- head/sys/arm/ti/am335x/am335x_gpio.c +++ head/sys/arm/ti/am335x/am335x_gpio.c @@ -155,3 +155,4 @@ sizeof(struct ti_gpio_softc), ti_gpio_driver); DRIVER_MODULE(am335x_gpio, simplebus, am335x_gpio_driver, am335x_gpio_devclass, 0, 0); +MODULE_DEPEND(am335x_gpio, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_lcd.c =================================================================== --- head/sys/arm/ti/am335x/am335x_lcd.c +++ head/sys/arm/ti/am335x/am335x_lcd.c @@ -50,6 +50,8 @@ #include +#include + #include #include #include @@ -65,7 +67,7 @@ #include #endif -#include +#include #include #include "am335x_lcd.h" @@ -219,6 +221,9 @@ /* HDMI framer */ phandle_t sc_hdmi_framer; eventhandler_tag sc_hdmi_evh; + + /* Clock */ + clk_t sc_clk_dpll_disp_ck; }; static void @@ -615,24 +620,28 @@ uint32_t hbp, hfp, hsw; uint32_t vbp, vfp, vsw; uint32_t width, height; - unsigned int ref_freq; + uint64_t ref_freq; int err; /* * try to adjust clock to get double of requested frequency * HDMI/DVI displays are very sensitive to error in frequncy value */ - if (ti_prcm_clk_set_source_freq(LCDC_CLK, sc->sc_panel.panel_pxl_clk*2)) { + + err = clk_set_freq(sc->sc_clk_dpll_disp_ck, sc->sc_panel.panel_pxl_clk*2, + CLK_SET_ROUND_ANY); + if (err != 0) { device_printf(sc->sc_dev, "can't set source frequency\n"); return (ENXIO); } - if (ti_prcm_clk_get_source_freq(LCDC_CLK, &ref_freq)) { + err = clk_get_freq(sc->sc_clk_dpll_disp_ck, &ref_freq); + if (err != 0) { device_printf(sc->sc_dev, "can't get reference frequency\n"); return (ENXIO); } - /* Panle initialization */ + /* Panel initialization */ dma_size = round_page(sc->sc_panel.panel_width*sc->sc_panel.panel_height*sc->sc_panel.bpp/8); /* @@ -967,6 +976,13 @@ return (ENXIO); } + /* Fixme: Cant find any reference in DTS for dpll_disp_ck@498 for now. */ + err = clk_get_by_name(dev, "dpll_disp_ck@498", &sc->sc_clk_dpll_disp_ck); + if (err != 0) { + device_printf(dev, "Cant get dpll_disp_ck@49\n"); + return (ENXIO); + } + sc->sc_panel.ac_bias = 255; sc->sc_panel.ac_bias_intrpt = 0; sc->sc_panel.dma_burst_sz = 16; @@ -989,7 +1005,11 @@ } } - ti_prcm_clk_enable(LCDC_CLK); + err = ti_sysc_clock_enable(device_get_parent(dev)); + if (err != 0) { + device_printf(dev, "Failed to enable sysc clkctrl, err %d\n", err); + return (ENXIO); + } rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, @@ -1081,3 +1101,4 @@ DRIVER_MODULE(am335x_lcd, simplebus, am335x_lcd_driver, am335x_lcd_devclass, 0, 0); MODULE_VERSION(am335x_lcd, 1); MODULE_DEPEND(am335x_lcd, simplebus, 1, 1, 1); +MODULE_DEPEND(am335x_lcd, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_musb.c =================================================================== --- head/sys/arm/ti/am335x/am335x_musb.c +++ head/sys/arm/ti/am335x/am335x_musb.c @@ -66,9 +66,11 @@ #include -#include -#include #include +#include +#include +#include +#include "syscon_if.h" #define USBCTRL_REV 0x00 #define USBCTRL_CTRL 0x14 @@ -130,6 +132,7 @@ struct musbotg_softc sc_otg; struct resource *sc_mem_res[2]; int sc_irq_rid; + struct syscon *syscon; }; static void @@ -155,30 +158,33 @@ musbotg_clocks_on(void *arg) { struct musbotg_softc *sc; - uint32_t c, reg; + struct musbotg_super_softc *ssc; + uint32_t reg; sc = arg; - reg = USB_CTRL[sc->sc_id]; + ssc = sc->sc_platform_data; - ti_scm_reg_read_4(reg, &c); - c &= ~3; /* Enable power */ - c |= 1 << 19; /* VBUS detect enable */ - c |= 1 << 20; /* Session end enable */ - ti_scm_reg_write_4(reg, c); + reg = SYSCON_READ_4(ssc->syscon, USB_CTRL[sc->sc_id]); + reg &= ~3; /* Enable power */ + reg |= 1 << 19; /* VBUS detect enable */ + reg |= 1 << 20; /* Session end enable */ + + SYSCON_WRITE_4(ssc->syscon, USB_CTRL[sc->sc_id], reg); } static void musbotg_clocks_off(void *arg) { struct musbotg_softc *sc; - uint32_t c, reg; + struct musbotg_super_softc *ssc; + uint32_t reg; sc = arg; - reg = USB_CTRL[sc->sc_id]; + ssc = sc->sc_platform_data; /* Disable power to PHY */ - ti_scm_reg_read_4(reg, &c); - ti_scm_reg_write_4(reg, c | 3); + reg = SYSCON_READ_4(ssc->syscon, USB_CTRL[sc->sc_id]); + SYSCON_WRITE_4(ssc->syscon, USB_CTRL[sc->sc_id], reg | 3); } static void @@ -241,9 +247,42 @@ char mode[16]; int err; uint32_t reg; + phandle_t opp_table; + clk_t clk_usbotg_fck; sc->sc_otg.sc_id = device_get_unit(dev); + /* FIXME: The devicetree needs to be updated to get a handle to the gate + * usbotg_fck@47c. see TRM 8.1.12.2 CM_WKUP CM_CLKDCOLDO_DPLL_PER. + */ + err = clk_get_by_name(dev, "usbotg_fck@47c", &clk_usbotg_fck); + if (err) { + device_printf(dev, "Can not find usbotg_fck@47c\n"); + return (ENXIO); + } + + err = clk_enable(clk_usbotg_fck); + if (err) { + device_printf(dev, "Can not enable usbotg_fck@47c\n"); + return (ENXIO); + } + + /* FIXME: For now; Go and kidnap syscon from opp-table */ + opp_table = OF_finddevice("/opp-table"); + if (opp_table == -1) { + device_printf(dev, "Cant find /opp-table\n"); + return (ENXIO); + } + if (!OF_hasprop(opp_table, "syscon")) { + device_printf(dev, "/opp-table missing syscon property\n"); + return (ENXIO); + } + err = syscon_get_by_ofw_property(dev, opp_table, "syscon", &sc->syscon); + if (err) { + device_printf(dev, "Failed to get syscon\n"); + return (ENXIO); + } + /* Request the memory resources */ err = bus_alloc_resources(dev, am335x_musbotg_mem_spec, sc->sc_mem_res); @@ -417,5 +456,7 @@ static devclass_t musbotg_devclass; -DRIVER_MODULE(musbotg, usbss, musbotg_driver, musbotg_devclass, 0, 0); -MODULE_DEPEND(musbotg, usbss, 1, 1, 1); +DRIVER_MODULE(musbotg, ti_sysc, musbotg_driver, musbotg_devclass, 0, 0); +MODULE_DEPEND(musbotg, ti_sysc, 1, 1, 1); +MODULE_DEPEND(musbotg, ti_am3359_cppi41, 1, 1, 1); +MODULE_DEPEND(usbss, usb, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_prcm.c =================================================================== --- head/sys/arm/ti/am335x/am335x_prcm.c +++ head/sys/arm/ti/am335x/am335x_prcm.c @@ -1,884 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * 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 "am335x_scm.h" - -#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; - int attach_done; -}; - -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); - - 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; - - return (0); -} - -static void -am335x_prcm_new_pass(device_t dev) -{ - struct am335x_prcm_softc *sc = device_get_softc(dev); - unsigned int sysclk, fclk; - - sc = device_get_softc(dev); - if (sc->attach_done || - bus_current_pass < (BUS_PASS_TIMER + BUS_PASS_ORDER_EARLY)) { - bus_generic_new_pass(dev); - return; - } - - sc->attach_done = 1; - - 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"); - goto fail; - } - - return; - -fail: - device_detach(dev); - return; -} - -static device_method_t am335x_prcm_methods[] = { - DEVMETHOD(device_probe, am335x_prcm_probe), - DEVMETHOD(device_attach, am335x_prcm_attach), - - /* Bus interface */ - DEVMETHOD(bus_new_pass, am335x_prcm_new_pass), - { 0, 0 } -}; - -static driver_t am335x_prcm_driver = { - "am335x_prcm", - am335x_prcm_methods, - sizeof(struct am335x_prcm_softc), -}; - -static devclass_t am335x_prcm_devclass; - -EARLY_DRIVER_MODULE(am335x_prcm, simplebus, am335x_prcm_driver, - am335x_prcm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); -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. */ - if (ti_scm_reg_read_4(SCM_CTRL_STATUS, &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/am335x/am335x_pwmss.c =================================================================== --- head/sys/arm/ti/am335x/am335x_pwmss.c +++ head/sys/arm/ti/am335x/am335x_pwmss.c @@ -46,10 +46,11 @@ #include #include -#include -#include -#include +#include +#include +#include "syscon_if.h" + #include "am335x_pwm.h" #include "am335x_scm.h" @@ -59,6 +60,11 @@ #define CLKCONFIG_EPWMCLK_EN (1 << 8) #define PWMSS_CLKSTATUS 0x0C +/* TRM chapter 2 memory map table 2-3 + VER register location */ +#define PWMSS_REV_0 0x0000 +#define PWMSS_REV_1 0x2000 +#define PWMSS_REV_2 0x4000 + static device_probe_t am335x_pwmss_probe; static device_attach_t am335x_pwmss_attach; static device_detach_t am335x_pwmss_detach; @@ -66,7 +72,7 @@ struct am335x_pwmss_softc { struct simplebus_softc sc_simplebus; device_t sc_dev; - clk_ident_t sc_clk; + struct syscon *syscon; }; static device_method_t am335x_pwmss_methods[] = { @@ -97,36 +103,45 @@ { struct am335x_pwmss_softc *sc; uint32_t reg, id; - phandle_t node; + uint64_t rev_address; + phandle_t node, opp_table; sc = device_get_softc(dev); sc->sc_dev = dev; - sc->sc_clk = ti_hwmods_get_clock(dev); - if (sc->sc_clk == INVALID_CLK_IDENT) { - device_printf(dev, "failed to get device id based on ti,hwmods\n"); - return (EINVAL); + /* FIXME: For now; Go and kidnap syscon from opp-table */ + opp_table = OF_finddevice("/opp-table"); + if (opp_table == -1) { + device_printf(dev, "Cant find /opp-table\n"); + return (ENXIO); } + if (!OF_hasprop(opp_table, "syscon")) { + device_printf(dev, "/opp-table doesnt have required syscon property\n"); + return (ENXIO); + } + if (syscon_get_by_ofw_property(dev, opp_table, "syscon", &sc->syscon) != 0) { + device_printf(dev, "Failed to get syscon\n"); + return (ENXIO); + } - ti_prcm_clk_enable(sc->sc_clk); - ti_scm_reg_read_4(SCM_PWMSS_CTRL, ®); - switch (sc->sc_clk) { - case PWMSS0_CLK: - id = 0; - break; - case PWMSS1_CLK: - id = 1; - break; + ti_sysc_clock_enable(device_get_parent(dev)); - case PWMSS2_CLK: - id = 2; - break; - default: - device_printf(dev, "unknown pwmss clock id: %d\n", sc->sc_clk); - return (EINVAL); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + switch (rev_address) { + case PWMSS_REV_0: + id = 0; + break; + case PWMSS_REV_1: + id = 1; + break; + case PWMSS_REV_2: + id = 2; + break; } + + reg = SYSCON_READ_4(sc->syscon, SCM_PWMSS_CTRL); reg |= (1 << id); - ti_scm_reg_write_4(SCM_PWMSS_CTRL, reg); + SYSCON_WRITE_4(sc->syscon, SCM_PWMSS_CTRL, reg); node = ofw_bus_get_node(dev); @@ -161,3 +176,4 @@ static devclass_t am335x_pwmss_devclass; DRIVER_MODULE(am335x_pwmss, simplebus, am335x_pwmss_driver, am335x_pwmss_devclass, 0, 0); MODULE_VERSION(am335x_pwmss, 1); +MODULE_DEPEND(am335x_pwmss, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_rtc.c =================================================================== --- head/sys/arm/ti/am335x/am335x_rtc.c +++ head/sys/arm/ti/am335x/am335x_rtc.c @@ -39,8 +39,9 @@ #include +#include #include -#include +#include #include #include @@ -110,7 +111,7 @@ RTC_LOCK_INIT(sc); /* Enable the RTC module. */ - ti_prcm_clk_enable(RTC_CLK); + ti_sysc_clock_enable(device_get_parent(dev)); rev = RTC_READ4(sc, RTC_REVISION); device_printf(dev, "AM335X RTC v%d.%d.%d\n", (rev >> 8) & 0x7, (rev >> 6) & 0x3, rev & 0x3f); @@ -209,3 +210,4 @@ DRIVER_MODULE(am335x_rtc, simplebus, am335x_rtc_driver, am335x_rtc_devclass, 0, 0); MODULE_VERSION(am335x_rtc, 1); MODULE_DEPEND(am335x_rtc, simplebus, 1, 1, 1); +MODULE_DEPEND(am335x_rtc, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_scm.c =================================================================== --- head/sys/arm/ti/am335x/am335x_scm.c +++ head/sys/arm/ti/am335x/am335x_scm.c @@ -40,11 +40,15 @@ #include #include +#include +#include "syscon_if.h" + #define TZ_ZEROC 2731 struct am335x_scm_softc { int sc_last_temp; struct sysctl_oid *sc_temp_oid; + struct syscon *syscon; }; static int @@ -60,7 +64,7 @@ /* Read the temperature and convert to Kelvin. */ for(i = 50; i > 0; i--) { - ti_scm_reg_read_4(SCM_BGAP_CTRL, ®); + reg = SYSCON_READ_4(sc->syscon, SCM_BGAP_CTRL); if ((reg & SCM_BGAP_EOCZ) == 0) break; DELAY(50); @@ -96,6 +100,9 @@ static int am335x_scm_probe(device_t dev) { + /* Just allow the first one */ + if (strcmp(device_get_nameunit(dev), "am335x_scm0") != 0) + return (ENXIO); device_set_desc(dev, "AM335x Control Module Extension"); @@ -109,21 +116,40 @@ struct sysctl_ctx_list *ctx; struct sysctl_oid_list *tree; uint32_t reg; + phandle_t opp_table; + int err; + sc = device_get_softc(dev); + + /* FIXME: For now; Go and kidnap syscon from opp-table */ + opp_table = OF_finddevice("/opp-table"); + if (opp_table == -1) { + device_printf(dev, "Cant find /opp-table\n"); + return (ENXIO); + } + if (!OF_hasprop(opp_table, "syscon")) { + device_printf(dev, "/opp-table missing syscon property\n"); + return (ENXIO); + } + err = syscon_get_by_ofw_property(dev, opp_table, "syscon", &sc->syscon); + if (err) { + device_printf(dev, "Failed to get syscon\n"); + return (ENXIO); + } + /* Reset the digital outputs. */ - ti_scm_reg_write_4(SCM_BGAP_CTRL, 0); - ti_scm_reg_read_4(SCM_BGAP_CTRL, ®); + SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, 0); + reg = SYSCON_READ_4(sc->syscon, SCM_BGAP_CTRL); DELAY(500); /* Set continous mode. */ - ti_scm_reg_write_4(SCM_BGAP_CTRL, SCM_BGAP_CONTCONV); - ti_scm_reg_read_4(SCM_BGAP_CTRL, ®); + SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, SCM_BGAP_CONTCONV); + reg = SYSCON_READ_4(sc->syscon, SCM_BGAP_CTRL); DELAY(500); /* Start the ADC conversion. */ reg = SCM_BGAP_CLRZ | SCM_BGAP_CONTCONV | SCM_BGAP_SOC; - ti_scm_reg_write_4(SCM_BGAP_CTRL, reg); + SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, reg); /* Temperature sysctl. */ - sc = device_get_softc(dev); ctx = device_get_sysctl_ctx(dev); tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); sc->sc_temp_oid = SYSCTL_ADD_PROC(ctx, tree, OID_AUTO, @@ -145,7 +171,7 @@ sysctl_remove_oid(sc->sc_temp_oid, 1, 0); /* Stop the bandgap ADC. */ - ti_scm_reg_write_4(SCM_BGAP_CTRL, SCM_BGAP_BGOFF); + SYSCON_WRITE_4(sc->syscon, SCM_BGAP_CTRL, SCM_BGAP_BGOFF); return (0); } @@ -169,4 +195,4 @@ DRIVER_MODULE(am335x_scm, ti_scm, am335x_scm_driver, am335x_scm_devclass, 0, 0); MODULE_VERSION(am335x_scm, 1); -MODULE_DEPEND(am335x_scm, ti_scm, 1, 1, 1); +MODULE_DEPEND(am335x_scm, ti_scm_syscon, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_usb_phy.c =================================================================== --- head/sys/arm/ti/am335x/am335x_usb_phy.c +++ head/sys/arm/ti/am335x/am335x_usb_phy.c @@ -0,0 +1,121 @@ +/*- + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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 +#include + +#include + +#include +#include + +#define TI_AM335X_USB_PHY 1 +#define TI_AM335X_USB_PHY_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,am335x-usb-phy", TI_AM335X_USB_PHY }, + { NULL, TI_AM335X_USB_PHY_END } +}; + +struct ti_usb_phy_softc { + device_t dev; +}; + +static int ti_usb_phy_probe(device_t dev); +static int ti_usb_phy_attach(device_t dev); +static int ti_usb_phy_detach(device_t dev); + +static int +ti_usb_phy_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI AM335x USB PHY"); + if (!bootverbose) + device_quiet(dev); + + return (BUS_PROBE_DEFAULT); +} + +static int +ti_usb_phy_attach(device_t dev) +{ + struct ti_usb_phy_softc *sc; + phandle_t node; + + sc = device_get_softc(dev); + sc->dev = dev; + node = ofw_bus_get_node(dev); + + /* FIXME: Add dev/extres/phy/ interface */ + + return (bus_generic_attach(dev)); +} + +static int +ti_usb_phy_detach(device_t dev) +{ + return (EBUSY); +} + +static device_method_t ti_usb_phy_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_usb_phy_probe), + DEVMETHOD(device_attach, ti_usb_phy_attach), + DEVMETHOD(device_detach, ti_usb_phy_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(ti_usb_phy, ti_usb_phy_driver, ti_usb_phy_methods, + sizeof(struct ti_usb_phy_softc), simplebus_driver); + +static devclass_t ti_usb_phy_devclass; + +EARLY_DRIVER_MODULE(ti_usb_phy, simplebus, ti_usb_phy_driver, + ti_usb_phy_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); +MODULE_VERSION(ti_usb_phy, 1); +MODULE_DEPEND(ti_usb_phy, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/am335x/am335x_usbss.c =================================================================== --- head/sys/arm/ti/am335x/am335x_usbss.c +++ head/sys/arm/ti/am335x/am335x_usbss.c @@ -1,226 +0,0 @@ -/*- - * SPDX-License-Identifier: BSD-2-Clause-FreeBSD - * - * Copyright (c) 2013 Oleksandr Tymoshenko - * - * 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 - -#include -#include - -#include -#include -#include -#include - -#include -#include -#include -#include - -#include - -#include -#include -#include - -#define AM335X_USB_PORTS 2 - -#define USBSS_REVREG 0x00 -#define USBSS_SYSCONFIG 0x10 -#define USBSS_SYSCONFIG_SRESET 1 - -#define USBCTRL_REV 0x00 -#define USBCTRL_CTRL 0x14 -#define USBCTRL_STAT 0x18 -#define USBCTRL_IRQ_STAT0 0x30 -#define IRQ_STAT0_RXSHIFT 16 -#define IRQ_STAT0_TXSHIFT 0 -#define USBCTRL_IRQ_STAT1 0x34 -#define IRQ_STAT1_DRVVBUS (1 << 8) -#define USBCTRL_INTEN_SET0 0x38 -#define USBCTRL_INTEN_SET1 0x3C -#define USBCTRL_INTEN_USB_ALL 0x1ff -#define USBCTRL_INTEN_USB_SOF (1 << 3) -#define USBCTRL_INTEN_CLR0 0x40 -#define USBCTRL_INTEN_CLR1 0x44 -#define USBCTRL_UTMI 0xE0 -#define USBCTRL_UTMI_FSDATAEXT (1 << 1) -#define USBCTRL_MODE 0xE8 -#define USBCTRL_MODE_IDDIG (1 << 8) -#define USBCTRL_MODE_IDDIGMUX (1 << 7) - -#define USBSS_WRITE4(sc, reg, val) \ - bus_write_4((sc)->sc_mem_res, (reg), (val)) -#define USBSS_READ4(sc, reg) \ - bus_read_4((sc)->sc_mem_res, (reg)) - -static device_probe_t usbss_probe; -static device_attach_t usbss_attach; -static device_detach_t usbss_detach; - -struct usbss_softc { - struct simplebus_softc simplebus_sc; - struct resource *sc_mem_res; - int sc_mem_rid; -}; - -static int -usbss_probe(device_t dev) -{ - - if (!ofw_bus_status_okay(dev)) - return (ENXIO); - - if (!ofw_bus_is_compatible(dev, "ti,am33xx-usb")) - return (ENXIO); - - device_set_desc(dev, "TI AM33xx integrated USB OTG controller"); - - return (BUS_PROBE_DEFAULT); -} - -static int -usbss_attach(device_t dev) -{ - struct usbss_softc *sc = device_get_softc(dev); - int i; - uint32_t rev; - phandle_t node; - - /* Request the memory resources */ - sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, - &sc->sc_mem_rid, RF_ACTIVE); - if (sc->sc_mem_res == NULL) { - device_printf(dev, - "Error: could not allocate mem resources\n"); - return (ENXIO); - } - - /* Enable device clocks. */ - ti_prcm_clk_enable(MUSB0_CLK); - - /* - * Reset USBSS, USB0 and USB1. - * The registers of USB subsystem must not be accessed while the - * reset pulse is active (200ns). - */ - USBSS_WRITE4(sc, USBSS_SYSCONFIG, USBSS_SYSCONFIG_SRESET); - DELAY(100); - i = 10; - while (USBSS_READ4(sc, USBSS_SYSCONFIG) & USBSS_SYSCONFIG_SRESET) { - DELAY(100); - if (i-- == 0) { - device_printf(dev, "reset timeout.\n"); - return (ENXIO); - } - } - - /* Read the module revision. */ - rev = USBSS_READ4(sc, USBSS_REVREG); - device_printf(dev, "TI AM335X USBSS v%d.%d.%d\n", - (rev >> 8) & 7, (rev >> 6) & 3, rev & 63); - - node = ofw_bus_get_node(dev); - - if (node == -1) { - usbss_detach(dev); - return (ENXIO); - } - - simplebus_init(dev, node); - - /* - * Allow devices to identify. - */ - bus_generic_probe(dev); - - /* - * Now walk the OFW tree and attach top-level devices. - */ - for (node = OF_child(node); node > 0; node = OF_peer(node)) - simplebus_add_device(dev, node, 0, NULL, -1, NULL); - - return (bus_generic_attach(dev)); -} - -static int -usbss_detach(device_t dev) -{ - struct usbss_softc *sc = device_get_softc(dev); - - /* Free resources if any */ - if (sc->sc_mem_res) - bus_release_resource(dev, SYS_RES_MEMORY, sc->sc_mem_rid, - sc->sc_mem_res); - - /* during module unload there are lots of children leftover */ - device_delete_children(dev); - - return (0); -} - -static device_method_t usbss_methods[] = { - /* Device interface */ - DEVMETHOD(device_probe, usbss_probe), - DEVMETHOD(device_attach, usbss_attach), - DEVMETHOD(device_detach, usbss_detach), - DEVMETHOD(device_suspend, bus_generic_suspend), - DEVMETHOD(device_resume, bus_generic_resume), - DEVMETHOD(device_shutdown, bus_generic_shutdown), - - DEVMETHOD_END -}; - -DEFINE_CLASS_1(usbss, usbss_driver, usbss_methods, - sizeof(struct usbss_softc), simplebus_driver); -static devclass_t usbss_devclass; -DRIVER_MODULE(usbss, simplebus, usbss_driver, usbss_devclass, 0, 0); -MODULE_DEPEND(usbss, usb, 1, 1, 1); Index: head/sys/arm/ti/am335x/files.am335x =================================================================== --- head/sys/arm/ti/am335x/files.am335x +++ head/sys/arm/ti/am335x/files.am335x @@ -8,7 +8,6 @@ arm/ti/am335x/am335x_lcd.c optional sc | vt arm/ti/am335x/am335x_lcd_syscons.c optional sc arm/ti/am335x/am335x_pmic.c optional am335x_pmic -arm/ti/am335x/am335x_prcm.c standard arm/ti/am335x/am335x_pwmss.c standard dev/pwm/pwmbus_if.m standard arm/ti/am335x/am335x_ehrpwm.c standard @@ -16,8 +15,9 @@ arm/ti/am335x/am335x_rtc.c optional am335x_rtc arm/ti/am335x/am335x_scm.c standard arm/ti/am335x/am335x_scm_padconf.c standard -arm/ti/am335x/am335x_usbss.c optional musb fdt arm/ti/am335x/am335x_musb.c optional musb fdt +arm/ti/am335x/am335x_usb_phy.c optional musb fdt +arm/ti/am335x/am3359_cppi41.c optional musb fdt arm/ti/am335x/tda19988.c optional hdmi Index: head/sys/arm/ti/clk/clock_common.h =================================================================== --- head/sys/arm/ti/clk/clock_common.h +++ head/sys/arm/ti/clk/clock_common.h @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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$"); + +struct clock_cell_info { + cell_t *clock_cells; + uint8_t *clock_cells_ncells; + uint32_t num_clock_cells; + uint8_t num_real_clocks; +}; + +void read_clock_cells(device_t dev, struct clock_cell_info *clk); +int find_parent_clock_names(device_t dev, struct clock_cell_info *clk, struct clknode_init_def *def); +void create_clkdef(device_t dev, struct clock_cell_info *clk, struct clknode_init_def *def); +void free_clkdef(struct clknode_init_def *def); Index: head/sys/arm/ti/clk/clock_common.c =================================================================== --- head/sys/arm/ti/clk/clock_common.c +++ head/sys/arm/ti/clk/clock_common.c @@ -0,0 +1,152 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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 +#include +#include + +#include "clock_common.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +void +read_clock_cells(device_t dev, struct clock_cell_info *clk) { + ssize_t numbytes_clocks; + phandle_t node, parent, *cells; + int index, ncells, rv; + + node = ofw_bus_get_node(dev); + + /* Get names of parent clocks */ + numbytes_clocks = OF_getproplen(node, "clocks"); + clk->num_clock_cells = numbytes_clocks / sizeof(cell_t); + + /* Allocate space and get clock cells content */ + /* clock_cells / clock_cells_ncells will be freed in + * find_parent_clock_names() + */ + clk->clock_cells = malloc(numbytes_clocks, M_DEVBUF, M_WAITOK|M_ZERO); + clk->clock_cells_ncells = malloc(clk->num_clock_cells*sizeof(uint8_t), + M_DEVBUF, M_WAITOK|M_ZERO); + OF_getencprop(node, "clocks", clk->clock_cells, numbytes_clocks); + + /* Count number of clocks */ + clk->num_real_clocks = 0; + for (index = 0; index < clk->num_clock_cells; index++) { + rv = ofw_bus_parse_xref_list_alloc(node, "clocks", "#clock-cells", + clk->num_real_clocks, &parent, &ncells, &cells); + if (rv != 0) + continue; + + if (cells != NULL) + OF_prop_free(cells); + + clk->clock_cells_ncells[index] = ncells; + index += ncells; + clk->num_real_clocks++; + } +} + +int +find_parent_clock_names(device_t dev, struct clock_cell_info *clk, struct clknode_init_def *def) { + int index, clock_index, err; + bool found_all = true; + clk_t parent; + + /* Figure out names */ + for (index = 0, clock_index = 0; index < clk->num_clock_cells; index++) { + /* Get name of parent clock */ + err = clk_get_by_ofw_index(dev, 0, clock_index, &parent); + if (err != 0) { + clock_index++; + found_all = false; + DPRINTF(dev, "Failed to find clock_cells[%d]=0x%x\n", + index, clk->clock_cells[index]); + + index += clk->clock_cells_ncells[index]; + continue; + } + + def->parent_names[clock_index] = clk_get_name(parent); + clk_release(parent); + + DPRINTF(dev, "Found parent clock[%d/%d]: %s\n", + clock_index, clk->num_real_clocks, + def->parent_names[clock_index]); + + clock_index++; + index += clk->clock_cells_ncells[index]; + } + + if (!found_all) { + return 1; + } + + free(clk->clock_cells, M_DEVBUF); + free(clk->clock_cells_ncells, M_DEVBUF); + return 0; +} + +void +create_clkdef(device_t dev, struct clock_cell_info *clk, struct clknode_init_def *def) { + def->id = 1; + + clk_parse_ofw_clk_name(dev, ofw_bus_get_node(dev), &def->name); + + DPRINTF(dev, "node name: %s\n", def->name); + + def->parent_cnt = clk->num_real_clocks; + def->parent_names = malloc(clk->num_real_clocks*sizeof(char *), + M_OFWPROP, M_WAITOK); +} +void +free_clkdef(struct clknode_init_def *def) { + OF_prop_free(__DECONST(char *, def->name)); + OF_prop_free(def->parent_names); +} Index: head/sys/arm/ti/clk/ti_clk_clkctrl.h =================================================================== --- head/sys/arm/ti/clk/ti_clk_clkctrl.h +++ head/sys/arm/ti/clk/ti_clk_clkctrl.h @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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$ + */ + +#ifndef _TI_CLK_CLKCTRL_H_ +#define _TI_CLK_CLKCTRL_H_ + +#include + +struct ti_clk_clkctrl_def { + struct clknode_init_def clkdef; + bool gdbclk; + uint32_t register_offset; +}; + +int ti_clknode_clkctrl_register(struct clkdom *clkdom, struct ti_clk_clkctrl_def *clkdef); + +#endif /* _TI_CLK_CLKCTRL_H_ */ Index: head/sys/arm/ti/clk/ti_clk_clkctrl.c =================================================================== --- head/sys/arm/ti/clk/ti_clk_clkctrl.c +++ head/sys/arm/ti/clk/ti_clk_clkctrl.c @@ -0,0 +1,219 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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 "clkdev_if.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * clknode for clkctrl, implements gate and mux (for gpioc) + */ + +#define GPIO_X_GDBCLK_MASK 0x00040000 +#define IDLEST_MASK 0x00030000 +#define MODULEMODE_MASK 0x00000003 + +#define GPIOX_GDBCLK_ENABLE 0x00040000 +#define GPIOX_GDBCLK_DISABLE 0x00000000 +#define IDLEST_FUNC 0x00000000 +#define IDLEST_TRANS 0x00010000 +#define IDLEST_IDLE 0x00020000 +#define IDLEST_DISABLE 0x00030000 + +#define MODULEMODE_DISABLE 0x0 +#define MODULEMODE_ENABLE 0x2 + +struct ti_clkctrl_clknode_sc { + device_t dev; + bool gdbclk; + /* omap4-cm range.host + ti,clkctrl reg[0] */ + uint32_t register_offset; +}; + +#define WRITE4(_clk, off, val) \ + CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) +#define READ4(_clk, off, val) \ + CLKDEV_READ_4(clknode_get_device(_clk), off, val) +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) + +static int +ti_clkctrl_init(struct clknode *clk, device_t dev) +{ + struct ti_clkctrl_clknode_sc *sc; + + sc = clknode_get_softc(clk); + sc->dev = dev; + + clknode_init_parent_idx(clk, 0); + return (0); +} + +static int +ti_clkctrl_set_gdbclk_gate(struct clknode *clk, bool enable) +{ + struct ti_clkctrl_clknode_sc *sc; + uint32_t val, gpio_x_gdbclk; + uint32_t timeout = 100; + + sc = clknode_get_softc(clk); + + READ4(clk, sc->register_offset, &val); + DPRINTF(sc->dev, "val(%x) & (%x | %x = %x)\n", + val, GPIO_X_GDBCLK_MASK, MODULEMODE_MASK, + GPIO_X_GDBCLK_MASK | MODULEMODE_MASK); + + if (enable) { + val = val & MODULEMODE_MASK; + val |= GPIOX_GDBCLK_ENABLE; + } else { + val = val & MODULEMODE_MASK; + val |= GPIOX_GDBCLK_DISABLE; + } + + DPRINTF(sc->dev, "val %x\n", val); + WRITE4(clk, sc->register_offset, val); + + /* Wait */ + while (timeout) { + READ4(clk, sc->register_offset, &val); + gpio_x_gdbclk = val & GPIO_X_GDBCLK_MASK; + if (enable && (gpio_x_gdbclk == GPIOX_GDBCLK_ENABLE)) + break; + else if (!enable && (gpio_x_gdbclk == GPIOX_GDBCLK_DISABLE)) + break; + DELAY(10); + timeout--; + } + if (timeout == 0) { + device_printf(sc->dev, "ti_clkctrl_set_gdbclk_gate: Timeout\n"); + return (1); + } + + return (0); +} + +static int +ti_clkctrl_set_gate(struct clknode *clk, bool enable) +{ + struct ti_clkctrl_clknode_sc *sc; + uint32_t val, idlest, module; + uint32_t timeout=100; + int err; + + sc = clknode_get_softc(clk); + + if (sc->gdbclk) { + err = ti_clkctrl_set_gdbclk_gate(clk, enable); + return (err); + } + + READ4(clk, sc->register_offset, &val); + + if (enable) + WRITE4(clk, sc->register_offset, MODULEMODE_ENABLE); + else + WRITE4(clk, sc->register_offset, MODULEMODE_DISABLE); + + while (timeout) { + READ4(clk, sc->register_offset, &val); + idlest = val & IDLEST_MASK; + module = val & MODULEMODE_MASK; + if (enable && + (idlest == IDLEST_FUNC || idlest == IDLEST_TRANS) && + module == MODULEMODE_ENABLE) + break; + else if (!enable && + idlest == IDLEST_DISABLE && + module == MODULEMODE_DISABLE) + break; + DELAY(10); + timeout--; + } + + if (timeout == 0) { + device_printf(sc->dev, "ti_clkctrl_set_gate: Timeout\n"); + return (1); + } + + return (0); +} + +static clknode_method_t ti_clkctrl_clknode_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, ti_clkctrl_init), + CLKNODEMETHOD(clknode_set_gate, ti_clkctrl_set_gate), + CLKNODEMETHOD_END +}; + +DEFINE_CLASS_1(ti_clkctrl_clknode, ti_clkctrl_clknode_class, + ti_clkctrl_clknode_methods, sizeof(struct ti_clkctrl_clknode_sc), + clknode_class); + +int +ti_clknode_clkctrl_register(struct clkdom *clkdom, + struct ti_clk_clkctrl_def *clkdef) +{ + struct clknode *clk; + struct ti_clkctrl_clknode_sc *sc; + + clk = clknode_create(clkdom, &ti_clkctrl_clknode_class, + &clkdef->clkdef); + + if (clk == NULL) { + return (1); + } + + sc = clknode_get_softc(clk); + sc->register_offset = clkdef->register_offset; + sc->gdbclk = clkdef->gdbclk; + + if (clknode_register(clkdom, clk) == NULL) { + return (2); + } + return (0); +} Index: head/sys/arm/ti/clk/ti_clk_dpll.h =================================================================== --- head/sys/arm/ti/clk/ti_clk_dpll.h +++ head/sys/arm/ti/clk/ti_clk_dpll.h @@ -0,0 +1,97 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2017 Emmanuel Vadot + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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$ + */ + +#ifndef _TI_DPLL_CLOCK_H_ +#define _TI_DPLL_CLOCK_H_ + +#include + +/* Registers are described in AM335x TRM chapter 8.1.12.2.* */ + +/* Register offsets */ +#define CM_CLKSEL_DPLL_PERIPH 0x49C + +/* CM_IDLEST_DPLL_xxx */ +#define ST_MN_BYPASS_MASK 0x0100 +#define ST_MN_BYPASS_SHIFT 8 +#define ST_DPLL_CLK_MASK 0x0001 + +/* CM_CLKMODE_DPLL_DPLL_EN feature flag */ +#define LOW_POWER_STOP_MODE_FLAG 0x01 +#define MN_BYPASS_MODE_FLAG 0x02 +#define IDLE_BYPASS_LOW_POWER_MODE_FLAG 0x04 +#define IDLE_BYPASS_FAST_RELOCK_MODE_FLAG 0x08 +#define LOCK_MODE_FLAG 0x10 + +/* CM_CLKMODE_DPLL_xxx */ +#define DPLL_EN_LOW_POWER_STOP_MODE 0x01 +#define DPLL_EN_MN_BYPASS_MODE 0x04 +#define DPLL_EN_IDLE_BYPASS_LOW_POWER_MODE 0x05 +#define DPLL_EN_IDLE_BYPASS_FAST_RELOCK_MODE 0x06 +#define DPLL_EN_LOCK_MODE 0x07 + + +#define TI_CLK_FACTOR_ZERO_BASED 0x0002 +#define TI_CLK_FACTOR_FIXED 0x0008 +#define TI_CLK_FACTOR_MIN_VALUE 0x0020 +#define TI_CLK_FACTOR_MAX_VALUE 0x0040 + +/* Based on aw_clk_factor sys/arm/allwinner/clkng/aw_clk.h */ +struct ti_clk_factor { + uint32_t shift; /* Shift bits for the factor */ + uint32_t mask; /* Mask to get the factor */ + uint32_t width; /* Number of bits for the factor */ + uint32_t value; /* Fixed value */ + + uint32_t min_value; + uint32_t max_value; + + uint32_t flags; /* Flags */ +}; + +struct ti_clk_dpll_def { + struct clknode_init_def clkdef; + + uint32_t ti_clkmode_offset; /* control */ + uint8_t ti_clkmode_flags; + + uint32_t ti_idlest_offset; + + uint32_t ti_clksel_offset; /* mult-div1 */ + struct ti_clk_factor ti_clksel_mult; + struct ti_clk_factor ti_clksel_div; + + uint32_t ti_autoidle_offset; +}; + +int ti_clknode_dpll_register(struct clkdom *clkdom, struct ti_clk_dpll_def *clkdef); + +#endif /* _TI_DPLL_CLOCK_H_ */ Index: head/sys/arm/ti/clk/ti_clk_dpll.c =================================================================== --- head/sys/arm/ti/clk/ti_clk_dpll.c +++ head/sys/arm/ti/clk/ti_clk_dpll.c @@ -0,0 +1,341 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Emmanuel Vadot + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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. + * + * based on sys/arm/allwinner/clkng/aw_clk_np.c + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include + +#include + +#include + +#include "clkdev_if.h" + +/* + * clknode for clocks matching the formula : + * + * clk = clkin * n / p + * + */ + +struct ti_dpll_clknode_sc { + uint32_t ti_clkmode_offset; /* control */ + uint8_t ti_clkmode_flags; + + uint32_t ti_idlest_offset; + + uint32_t ti_clksel_offset; /* mult-div1 */ + struct ti_clk_factor n; /* ti_clksel_mult */ + struct ti_clk_factor p; /* ti_clksel_div */ + + uint32_t ti_autoidle_offset; +}; + +#define WRITE4(_clk, off, val) \ + CLKDEV_WRITE_4(clknode_get_device(_clk), off, val) +#define READ4(_clk, off, val) \ + CLKDEV_READ_4(clknode_get_device(_clk), off, val) +#define DEVICE_LOCK(_clk) \ + CLKDEV_DEVICE_LOCK(clknode_get_device(_clk)) +#define DEVICE_UNLOCK(_clk) \ + CLKDEV_DEVICE_UNLOCK(clknode_get_device(_clk)) + +static int +ti_dpll_clk_init(struct clknode *clk, device_t dev) +{ + struct ti_dpll_clknode_sc *sc; + + sc = clknode_get_softc(clk); + + clknode_init_parent_idx(clk, 0); + return (0); +} + +/* helper to keep aw_clk_np_find_best "intact" */ +static inline uint32_t +ti_clk_factor_get_max(struct ti_clk_factor *factor) +{ + uint32_t max; + + if (factor->flags & TI_CLK_FACTOR_FIXED) + max = factor->value; + else { + max = (1 << factor->width); + } + + return (max); +} + +static inline uint32_t +ti_clk_factor_get_min(struct ti_clk_factor *factor) +{ + uint32_t min; + + if (factor->flags & TI_CLK_FACTOR_FIXED) + min = factor->value; + else if (factor->flags & TI_CLK_FACTOR_ZERO_BASED) + min = 0; + else if (factor->flags & TI_CLK_FACTOR_MIN_VALUE) + min = factor->min_value; + else + min = 1; + + return (min); +} + +static uint64_t +ti_dpll_clk_find_best(struct ti_dpll_clknode_sc *sc, uint64_t fparent, + uint64_t *fout, uint32_t *factor_n, uint32_t *factor_p) +{ + uint64_t cur, best; + uint32_t n, p, max_n, max_p, min_n, min_p; + + *factor_n = *factor_p = 0; + + max_n = ti_clk_factor_get_max(&sc->n); + max_p = ti_clk_factor_get_max(&sc->p); + min_n = ti_clk_factor_get_min(&sc->n); + min_p = ti_clk_factor_get_min(&sc->p); + + for (p = min_p; p <= max_p; ) { + for (n = min_n; n <= max_n; ) { + cur = fparent * n / p; + if (abs(*fout - cur) < abs(*fout - best)) { + best = cur; + *factor_n = n; + *factor_p = p; + } + + n++; + } + p++; + } + + return (best); +} + +static inline uint32_t +ti_clk_get_factor(uint32_t val, struct ti_clk_factor *factor) +{ + uint32_t factor_val; + + if (factor->flags & TI_CLK_FACTOR_FIXED) + return (factor->value); + + factor_val = (val & factor->mask) >> factor->shift; + if (!(factor->flags & TI_CLK_FACTOR_ZERO_BASED)) + factor_val += 1; + + return (factor_val); +} + +static inline uint32_t +ti_clk_factor_get_value(struct ti_clk_factor *factor, uint32_t raw) +{ + uint32_t val; + + if (factor->flags & TI_CLK_FACTOR_FIXED) + return (factor->value); + + if (factor->flags & TI_CLK_FACTOR_ZERO_BASED) + val = raw; + else if (factor->flags & TI_CLK_FACTOR_MAX_VALUE && + raw > factor->max_value) + val = factor->max_value; + else + val = raw - 1; + + return (val); +} + + +static int +ti_dpll_clk_set_freq(struct clknode *clk, uint64_t fparent, uint64_t *fout, + int flags, int *stop) +{ + struct ti_dpll_clknode_sc *sc; + uint64_t cur, best; + uint32_t val, n, p, best_n, best_p, timeout; + + sc = clknode_get_softc(clk); + + best = cur = 0; + + best = ti_dpll_clk_find_best(sc, fparent, fout, + &best_n, &best_p); + + if ((flags & CLK_SET_DRYRUN) != 0) { + *fout = best; + *stop = 1; + return (0); + } + + if ((best < *fout) && + (flags == CLK_SET_ROUND_DOWN)) { + *stop = 1; + return (ERANGE); + } + if ((best > *fout) && + (flags == CLK_SET_ROUND_UP)) { + *stop = 1; + return (ERANGE); + } + + DEVICE_LOCK(clk); + /* 1 switch PLL to bypass mode */ + WRITE4(clk, sc->ti_clkmode_offset, DPLL_EN_MN_BYPASS_MODE); + + /* 2 Ensure PLL is in bypass */ + timeout = 10000; + do { + DELAY(10); + READ4(clk, sc->ti_idlest_offset, &val); + } while (!(val & ST_MN_BYPASS_MASK) && timeout--); + + if (timeout == 0) { + DEVICE_UNLOCK(clk); + return (ERANGE); // FIXME: Better return value? + } + + /* 3 Set DPLL_MULT & DPLL_DIV bits */ + READ4(clk, sc->ti_clksel_offset, &val); + + n = ti_clk_factor_get_value(&sc->n, best_n); + p = ti_clk_factor_get_value(&sc->p, best_p); + val &= ~sc->n.mask; + val &= ~sc->p.mask; + val |= n << sc->n.shift; + val |= p << sc->p.shift; + + WRITE4(clk, sc->ti_clksel_offset, val); + + /* 4. configure M2, M4, M5 and M6 */ + /* + * FIXME: According to documentation M2/M4/M5/M6 can be set "later" + * See note in TRM 8.1.6.7.1 + */ + + /* 5 Switch over to lock mode */ + WRITE4(clk, sc->ti_clkmode_offset, DPLL_EN_LOCK_MODE); + + /* 6 Ensure PLL is locked */ + timeout = 10000; + do { + DELAY(10); + READ4(clk, sc->ti_idlest_offset, &val); + } while (!(val & ST_DPLL_CLK_MASK) && timeout--); + + DEVICE_UNLOCK(clk); + if (timeout == 0) { + return (ERANGE); // FIXME: Better return value? + } + + *fout = best; + *stop = 1; + + return (0); +} + +static int +ti_dpll_clk_recalc(struct clknode *clk, uint64_t *freq) +{ + struct ti_dpll_clknode_sc *sc; + uint32_t val, n, p; + + sc = clknode_get_softc(clk); + + DEVICE_LOCK(clk); + READ4(clk, sc->ti_clksel_offset, &val); + DEVICE_UNLOCK(clk); + + n = ti_clk_get_factor(val, &sc->n); + p = ti_clk_get_factor(val, &sc->p); + + *freq = *freq * n / p; + + return (0); +} + +static clknode_method_t ti_dpll_clknode_methods[] = { + /* Device interface */ + CLKNODEMETHOD(clknode_init, ti_dpll_clk_init), + CLKNODEMETHOD(clknode_recalc_freq, ti_dpll_clk_recalc), + CLKNODEMETHOD(clknode_set_freq, ti_dpll_clk_set_freq), + CLKNODEMETHOD_END +}; + +DEFINE_CLASS_1(ti_dpll_clknode, ti_dpll_clknode_class, ti_dpll_clknode_methods, + sizeof(struct ti_dpll_clknode_sc), clknode_class); + +int +ti_clknode_dpll_register(struct clkdom *clkdom, struct ti_clk_dpll_def *clkdef) +{ + struct clknode *clk; + struct ti_dpll_clknode_sc *sc; + + clk = clknode_create(clkdom, &ti_dpll_clknode_class, &clkdef->clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + + sc->ti_clkmode_offset = clkdef->ti_clkmode_offset; + sc->ti_clkmode_flags = clkdef->ti_clkmode_flags; + sc->ti_idlest_offset = clkdef->ti_idlest_offset; + sc->ti_clksel_offset = clkdef->ti_clksel_offset; + + sc->n.shift = clkdef->ti_clksel_mult.shift; + sc->n.mask = clkdef->ti_clksel_mult.mask; + sc->n.width = clkdef->ti_clksel_mult.width; + sc->n.value = clkdef->ti_clksel_mult.value; + sc->n.min_value = clkdef->ti_clksel_mult.min_value; + sc->n.max_value = clkdef->ti_clksel_mult.max_value; + sc->n.flags = clkdef->ti_clksel_mult.flags; + + sc->p.shift = clkdef->ti_clksel_div.shift; + sc->p.mask = clkdef->ti_clksel_div.mask; + sc->p.width = clkdef->ti_clksel_div.width; + sc->p.value = clkdef->ti_clksel_div.value; + sc->p.min_value = clkdef->ti_clksel_div.min_value; + sc->p.max_value = clkdef->ti_clksel_div.max_value; + sc->p.flags = clkdef->ti_clksel_div.flags; + + sc->ti_autoidle_offset = clkdef->ti_autoidle_offset; + + clknode_register(clkdom, clk); + + return (0); +} Index: head/sys/arm/ti/clk/ti_clkctrl.c =================================================================== --- head/sys/arm/ti/clk/ti_clkctrl.c +++ head/sys/arm/ti/clk/ti_clkctrl.c @@ -0,0 +1,353 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright 2016 Michal Meloun + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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 +#include + +#include + +#include +#include + +#include +#include +#include + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +#define L4LS_CLKCTRL_38 2 +#define L4_WKUP_CLKCTRL_0 1 +#define NO_SPECIAL_REG 0 + +/* Documentation/devicetree/bindings/clock/ti-clkctrl.txt */ + +#define TI_CLKCTRL_L4_WKUP 5 +#define TI_CLKCTRL_L4_SECURE 4 +#define TI_CLKCTRL_L4_PER 3 +#define TI_CLKCTRL_L4_CFG 2 +#define TI_CLKCTRL 1 +#define TI_CLKCTRL_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,clkctrl-l4-wkup", TI_CLKCTRL_L4_WKUP }, + { "ti,clkctrl-l4-secure", TI_CLKCTRL_L4_SECURE }, + { "ti,clkctrl-l4-per", TI_CLKCTRL_L4_PER }, + { "ti,clkctrl-l4-cfg", TI_CLKCTRL_L4_CFG }, + { "ti,clkctrl", TI_CLKCTRL }, + { NULL, TI_CLKCTRL_END } +}; + +struct ti_clkctrl_softc { + device_t dev; + + struct clkdom *clkdom; +}; + +static int ti_clkctrl_probe(device_t dev); +static int ti_clkctrl_attach(device_t dev); +static int ti_clkctrl_detach(device_t dev); +int clkctrl_ofw_map(struct clkdom *clkdom, uint32_t ncells, + phandle_t *cells, struct clknode **clk); +static int +create_clkctrl(struct ti_clkctrl_softc *sc, cell_t *reg, uint32_t index, uint32_t reg_offset, + uint64_t parent_offset, const char *org_name, bool special_gdbclk_reg); + +static int +ti_clkctrl_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI clkctrl"); + + return (BUS_PROBE_DEFAULT); +} + +static int +ti_clkctrl_attach(device_t dev) +{ + struct ti_clkctrl_softc *sc; + phandle_t node; + cell_t *reg; + ssize_t numbytes_reg; + int num_reg, err, ti_clock_cells; + uint32_t index, reg_offset, reg_address; + const char *org_name; + uint64_t parent_offset; + uint8_t special_reg = NO_SPECIAL_REG; + + sc = device_get_softc(dev); + sc->dev = dev; + node = ofw_bus_get_node(dev); + + /* Sanity check */ + err = OF_searchencprop(node, "#clock-cells", + &ti_clock_cells, sizeof(ti_clock_cells)); + if (err == -1) { + device_printf(sc->dev, "Failed to get #clock-cells\n"); + return (ENXIO); + } + + if (ti_clock_cells != 2) { + device_printf(sc->dev, "clock cells(%d) != 2\n", + ti_clock_cells); + return (ENXIO); + } + + /* Grab the content of reg properties */ + numbytes_reg = OF_getproplen(node, "reg"); + if (numbytes_reg == 0) { + device_printf(sc->dev, "reg property empty - check your devicetree\n"); + return (ENXIO); + } + num_reg = numbytes_reg / sizeof(cell_t); + + reg = malloc(numbytes_reg, M_DEVBUF, M_WAITOK); + OF_getencprop(node, "reg", reg, numbytes_reg); + + /* Create clock domain */ + sc->clkdom = clkdom_create(sc->dev); + if (sc->clkdom == NULL) { + free(reg, M_DEVBUF); + DPRINTF(sc->dev, "Failed to create clkdom\n"); + return (ENXIO); + } + clkdom_set_ofw_mapper(sc->clkdom, clkctrl_ofw_map); + + /* Create clock nodes */ + /* name */ + clk_parse_ofw_clk_name(sc->dev, node, &org_name); + + /* Get parent range */ + parent_offset = ti_omap4_cm_get_simplebus_base_host(device_get_parent(dev)); + + /* Check if this is a clkctrl with special registers like gpio */ + switch (ti_chip()) { +#ifdef SOC_OMAP4 + case CHIP_OMAP_4: + /* FIXME: Todo */ + break; + +#endif /* SOC_OMAP4 */ +#ifdef SOC_TI_AM335X + /* Checkout TRM 8.1.12.1.29 - 8.1.12.31 and 8.1.12.2.3 + * and the DTS. + */ + case CHIP_AM335X: + if (strcmp(org_name, "l4ls-clkctrl@38") == 0) + special_reg = L4LS_CLKCTRL_38; + else if (strcmp(org_name, "l4-wkup-clkctrl@0") == 0) + special_reg = L4_WKUP_CLKCTRL_0; + break; +#endif /* SOC_TI_AM335X */ + default: + break; + } + + /* reg property has a pair of (base address, length) */ + for (index = 0; index < num_reg; index += 2) { + for (reg_offset = 0; reg_offset < reg[index+1]; reg_offset += sizeof(cell_t)) { + + err = create_clkctrl(sc, reg, index, reg_offset, parent_offset, + org_name, false); + if (err) + goto cleanup; + + /* Create special clkctrl for GDBCLK in GPIO registers */ + switch (special_reg) { + case NO_SPECIAL_REG: + break; + case L4LS_CLKCTRL_38: + reg_address = reg[index] + reg_offset-reg[0]; + if (reg_address == 0x74 || + reg_address == 0x78 || + reg_address == 0x7C) + { + err = create_clkctrl(sc, reg, index, reg_offset, + parent_offset, org_name, true); + if (err) + goto cleanup; + } + break; + case L4_WKUP_CLKCTRL_0: + reg_address = reg[index] + reg_offset - reg[0]; + if (reg_address == 0x8) + { + err = create_clkctrl(sc, reg, index, reg_offset, + parent_offset, org_name, true); + if (err) + goto cleanup; + } + break; + } /* switch (special_reg) */ + } /* inner for */ + } /* for */ + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->dev, "Clk domain finit fails %x.\n", err); + err = ENXIO; + goto cleanup; + } + +cleanup: + OF_prop_free(__DECONST(char *, org_name)); + + free(reg, M_DEVBUF); + + if (err) + return (err); + + return (bus_generic_attach(dev)); +} + +static int +ti_clkctrl_detach(device_t dev) +{ + return (EBUSY); +} + +/* modified version of default mapper from clk.c */ +int +clkctrl_ofw_map(struct clkdom *clkdom, uint32_t ncells, + phandle_t *cells, struct clknode **clk) { + if (ncells == 0) + *clk = clknode_find_by_id(clkdom, 1); + else if (ncells == 1) + *clk = clknode_find_by_id(clkdom, cells[0]); + else if (ncells == 2) { + /* To avoid collision with other IDs just add one. + * All other registers has an offset of 4 from each other. + */ + if (cells[1]) + *clk = clknode_find_by_id(clkdom, cells[0]+1); + else + *clk = clknode_find_by_id(clkdom, cells[0]); + } + else + return (ERANGE); + + if (*clk == NULL) + return (ENXIO); + + return (0); +} + +static int +create_clkctrl(struct ti_clkctrl_softc *sc, cell_t *reg, uint32_t index, uint32_t reg_offset, + uint64_t parent_offset, const char *org_name, bool special_gdbclk_reg) { + struct ti_clk_clkctrl_def def; + char *name; + size_t name_len; + int err; + + name_len = strlen(org_name) + 1 + 5; /* 5 = _xxxx */ + name = malloc(name_len, M_OFWPROP, M_WAITOK); + + /* + * Check out XX_CLKCTRL-INDEX(offset)-macro dance in + * sys/gnu/dts/dts/include/dt-bindings/clock/am3.h + * sys/gnu/dts/dts/include/dt-bindings/clock/am4.h + * sys/gnu/dts/dts/include/dt-bindings/clock/dra7.h + * reg[0] are in practice the same as the offset described in the dts. + */ + /* special_gdbclk_reg are 0 or 1 */ + def.clkdef.id = reg[index] + reg_offset - reg[0] + special_gdbclk_reg; + def.register_offset = parent_offset + reg[index] + reg_offset; + + /* Indicate this clkctrl is special and dont use IDLEST/MODULEMODE */ + def.gdbclk = special_gdbclk_reg; + + /* Make up an uniq name in the namespace for each clkctrl */ + snprintf(name, name_len, "%s_%x", + org_name, def.clkdef.id); + def.clkdef.name = (const char *) name; + + DPRINTF(sc->dev, "ti_clkctrl_attach: reg[%d]: %s %x\n", + index, def.clkdef.name, def.clkdef.id); + + /* No parent name */ + def.clkdef.parent_cnt = 0; + + /* set flags */ + def.clkdef.flags = 0x0; + + /* Register the clkctrl */ + err = ti_clknode_clkctrl_register(sc->clkdom, &def); + if (err) { + DPRINTF(sc->dev, + "ti_clknode_clkctrl_register[%d:%d] failed %x\n", + index, reg_offset, err); + err = ENXIO; + } + OF_prop_free(name); + return (err); +} + +static device_method_t ti_clkctrl_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_clkctrl_probe), + DEVMETHOD(device_attach, ti_clkctrl_attach), + DEVMETHOD(device_detach, ti_clkctrl_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_clkctrl, ti_clkctrl_driver, ti_clkctrl_methods, + sizeof(struct ti_clkctrl_softc)); + +static devclass_t ti_clkctrl_devclass; + +EARLY_DRIVER_MODULE(ti_clkctrl, simplebus, ti_clkctrl_driver, +ti_clkctrl_devclass, 0, 0, BUS_PASS_BUS+BUS_PASS_ORDER_MIDDLE); + +MODULE_VERSION(ti_clkctrl, 1); Index: head/sys/arm/ti/clk/ti_divider_clock.c =================================================================== --- head/sys/arm/ti/clk/ti_divider_clock.c +++ head/sys/arm/ti/clk/ti_divider_clock.c @@ -0,0 +1,264 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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 + +#include "clock_common.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * Devicetree description + * Documentation/devicetree/bindings/clock/ti/divider.txt + */ + +struct ti_divider_softc { + device_t sc_dev; + bool attach_done; + struct clk_div_def div_def; + + struct clock_cell_info clock_cell; + struct clkdom *clkdom; +}; + +static int ti_divider_probe(device_t dev); +static int ti_divider_attach(device_t dev); +static int ti_divider_detach(device_t dev); + +#define TI_DIVIDER_CLOCK 2 +#define TI_COMPOSITE_DIVIDER_CLOCK 1 +#define TI_DIVIDER_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,divider-clock", TI_DIVIDER_CLOCK }, + { "ti,composite-divider-clock", TI_COMPOSITE_DIVIDER_CLOCK }, + { NULL, TI_DIVIDER_END } +}; + +static int +register_clk(struct ti_divider_softc *sc) { + int err; + + sc->clkdom = clkdom_create(sc->sc_dev); + if (sc->clkdom == NULL) { + DPRINTF(sc->sc_dev, "Failed to create clkdom\n"); + return (ENXIO); + } + + err = clknode_div_register(sc->clkdom, &sc->div_def); + if (err) { + DPRINTF(sc->sc_dev, "clknode_div_register failed %x\n", err); + return (ENXIO); + } + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->sc_dev, "Clk domain finit fails %x.\n", err); + return (ENXIO); + } + + return (0); +} + +static int +ti_divider_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI Divider Clock"); + + return (BUS_PROBE_DEFAULT); +} + +static int +ti_divider_attach(device_t dev) +{ + struct ti_divider_softc *sc; + phandle_t node; + int err; + cell_t value; + uint32_t ti_max_div; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + node = ofw_bus_get_node(dev); + + /* Grab the content of reg properties */ + OF_getencprop(node, "reg", &value, sizeof(value)); + sc->div_def.offset = value; + + if (OF_hasprop(node, "ti,bit-shift")) { + OF_getencprop(node, "ti,bit-shift", &value, sizeof(value)); + sc->div_def.i_shift = value; + } + + if (OF_hasprop(node, "ti,index-starts-at-one")) { + sc->div_def.div_flags = CLK_DIV_ZERO_BASED; + } + + if (OF_hasprop(node, "ti,index-power-of-two")) { + /* FIXME: later */ + device_printf(sc->sc_dev, "ti,index-power-of-two - Not implemented\n"); + /* remember to update i_width a few lines below */ + } + if (OF_hasprop(node, "ti,max-div")) { + OF_getencprop(node, "ti,max-div", &value, sizeof(value)); + ti_max_div = value; + } + + if (OF_hasprop(node, "clock-output-names")) + device_printf(sc->sc_dev, "clock-output-names\n"); + if (OF_hasprop(node, "ti,dividers")) + device_printf(sc->sc_dev, "ti,dividers\n"); + if (OF_hasprop(node, "ti,min-div")) + device_printf(sc->sc_dev, "ti,min-div - Not implemented\n"); + + if (OF_hasprop(node, "ti,autoidle-shift")) + device_printf(sc->sc_dev, "ti,autoidle-shift - Not implemented\n"); + if (OF_hasprop(node, "ti,set-rate-parent")) + device_printf(sc->sc_dev, "ti,set-rate-parent - Not implemented\n"); + if (OF_hasprop(node, "ti,latch-bit")) + device_printf(sc->sc_dev, "ti,latch-bit - Not implemented\n"); + + /* Figure out the width from ti_max_div */ + if (sc->div_def.div_flags) + sc->div_def.i_width = fls(ti_max_div-1); + else + sc->div_def.i_width = fls(ti_max_div); + + DPRINTF(sc->sc_dev, "div_def.i_width %x\n", sc->div_def.i_width); + + read_clock_cells(sc->sc_dev, &sc->clock_cell); + + create_clkdef(sc->sc_dev, &sc->clock_cell, &sc->div_def.clkdef); + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->div_def.clkdef); + + if (err) { + /* free_clkdef will be called in ti_divider_new_pass */ + DPRINTF(sc->sc_dev, "find_parent_clock_names failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + err = register_clk(sc); + + if (err) { + /* free_clkdef will be called in ti_divider_new_pass */ + DPRINTF(sc->sc_dev, "register_clk failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + sc->attach_done = true; + + free_clkdef(&sc->div_def.clkdef); + + return (bus_generic_attach(sc->sc_dev)); +} + +static int +ti_divider_detach(device_t dev) +{ + return (EBUSY); +} + +static void +ti_divider_new_pass(device_t dev) +{ + struct ti_divider_softc *sc; + int err; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + return; + } + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->div_def.clkdef); + if (err) { + /* free_clkdef will be called in a later call to ti_divider_new_pass */ + DPRINTF(sc->sc_dev, "new_pass find_parent_clock_names failed\n"); + return; + } + + err = register_clk(sc); + if (err) { + /* free_clkdef will be called in a later call to ti_divider_new_pass */ + DPRINTF(sc->sc_dev, "new_pass register_clk failed\n"); + return; + } + + sc->attach_done = true; + + free_clkdef(&sc->div_def.clkdef); +} + +static device_method_t ti_divider_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_divider_probe), + DEVMETHOD(device_attach, ti_divider_attach), + DEVMETHOD(device_detach, ti_divider_detach), + + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_divider_new_pass), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_divider, ti_divider_driver, ti_divider_methods, + sizeof(struct ti_divider_softc)); + +static devclass_t ti_divider_devclass; + +EARLY_DRIVER_MODULE(ti_divider, simplebus, ti_divider_driver, + ti_divider_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_divider, 1); Index: head/sys/arm/ti/clk/ti_dpll_clock.c =================================================================== --- head/sys/arm/ti/clk/ti_dpll_clock.c +++ head/sys/arm/ti/clk/ti_dpll_clock.c @@ -0,0 +1,375 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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 + +#include +#include "clock_common.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * Devicetree description + * Documentation/devicetree/bindings/clock/ti/dpll.txt + */ + +struct ti_dpll_softc { + device_t dev; + uint8_t dpll_type; + + bool attach_done; + struct ti_clk_dpll_def dpll_def; + + struct clock_cell_info clock_cell; + struct clkdom *clkdom; +}; + +static int ti_dpll_probe(device_t dev); +static int ti_dpll_attach(device_t dev); +static int ti_dpll_detach(device_t dev); + +#define TI_OMAP3_DPLL_CLOCK 17 +#define TI_OMAP3_DPLL_CORE_CLOCK 16 +#define TI_OMAP3_DPLL_PER_CLOCK 15 +#define TI_OMAP3_DPLL_PER_J_TYPE_CLOCK 14 +#define TI_OMAP4_DPLL_CLOCK 13 +#define TI_OMAP4_DPLL_X2_CLOCK 12 +#define TI_OMAP4_DPLL_CORE_CLOCK 11 +#define TI_OMAP4_DPLL_M4XEN_CLOCK 10 +#define TI_OMAP4_DPLL_J_TYPE_CLOCK 9 +#define TI_OMAP5_MPU_DPLL_CLOCK 8 +#define TI_AM3_DPLL_NO_GATE_CLOCK 7 +#define TI_AM3_DPLL_J_TYPE_CLOCK 6 +#define TI_AM3_DPLL_NO_GATE_J_TYPE_CLOCK 5 +#define TI_AM3_DPLL_CLOCK 4 +#define TI_AM3_DPLL_CORE_CLOCK 3 +#define TI_AM3_DPLL_X2_CLOCK 2 +#define TI_OMAP2_DPLL_CORE_CLOCK 1 +#define TI_DPLL_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,omap3-dpll-clock", TI_OMAP3_DPLL_CLOCK }, + { "ti,omap3-dpll-core-clock", TI_OMAP3_DPLL_CORE_CLOCK }, + { "ti,omap3-dpll-per-clock", TI_OMAP3_DPLL_PER_CLOCK }, + { "ti,omap3-dpll-per-j-type-clock",TI_OMAP3_DPLL_PER_J_TYPE_CLOCK }, + { "ti,omap4-dpll-clock", TI_OMAP4_DPLL_CLOCK }, + { "ti,omap4-dpll-x2-clock", TI_OMAP4_DPLL_X2_CLOCK }, + { "ti,omap4-dpll-core-clock", TI_OMAP4_DPLL_CORE_CLOCK }, + { "ti,omap4-dpll-m4xen-clock", TI_OMAP4_DPLL_M4XEN_CLOCK }, + { "ti,omap4-dpll-j-type-clock", TI_OMAP4_DPLL_J_TYPE_CLOCK }, + { "ti,omap5-mpu-dpll-clock", TI_OMAP5_MPU_DPLL_CLOCK }, + { "ti,am3-dpll-no-gate-clock", TI_AM3_DPLL_NO_GATE_CLOCK }, + { "ti,am3-dpll-j-type-clock", TI_AM3_DPLL_J_TYPE_CLOCK }, + { "ti,am3-dpll-no-gate-j-type-clock",TI_AM3_DPLL_NO_GATE_J_TYPE_CLOCK }, + { "ti,am3-dpll-clock", TI_AM3_DPLL_CLOCK }, + { "ti,am3-dpll-core-clock", TI_AM3_DPLL_CORE_CLOCK }, + { "ti,am3-dpll-x2-clock", TI_AM3_DPLL_X2_CLOCK }, + { "ti,omap2-dpll-core-clock", TI_OMAP2_DPLL_CORE_CLOCK }, + { NULL, TI_DPLL_END } +}; + +static int +register_clk(struct ti_dpll_softc *sc) { + int err; + + sc->clkdom = clkdom_create(sc->dev); + if (sc->clkdom == NULL) { + DPRINTF(sc->dev, "Failed to create clkdom\n"); + return (ENXIO); + } + + err = ti_clknode_dpll_register(sc->clkdom, &sc->dpll_def); + if (err) { + DPRINTF(sc->dev, + "ti_clknode_dpll_register failed %x\n", err); + return (ENXIO); + } + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->dev, "Clk domain finit fails %x.\n", err); + return (ENXIO); + } + + return (0); +} + +static int +ti_dpll_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI DPLL Clock"); + + return (BUS_PROBE_DEFAULT); +} + +static int +parse_dpll_reg(struct ti_dpll_softc *sc) { + ssize_t numbytes_regs; + uint32_t num_regs; + phandle_t node; + cell_t reg_cells[4]; + + if (sc->dpll_type == TI_AM3_DPLL_X2_CLOCK || + sc->dpll_type == TI_OMAP4_DPLL_X2_CLOCK) { + sc->dpll_def.ti_clksel_mult.value = 2; + sc->dpll_def.ti_clksel_mult.flags = TI_CLK_FACTOR_FIXED; + + sc->dpll_def.ti_clksel_div.value = 1; + sc->dpll_def.ti_clksel_div.flags = TI_CLK_FACTOR_FIXED; + return (0); + } + + node = ofw_bus_get_node(sc->dev); + + numbytes_regs = OF_getproplen(node, "reg"); + num_regs = numbytes_regs / sizeof(cell_t); + + /* Sanity check */ + if (num_regs > 4) + return (ENXIO); + + OF_getencprop(node, "reg", reg_cells, numbytes_regs); + + switch (sc->dpll_type) { + case TI_AM3_DPLL_NO_GATE_CLOCK: + case TI_AM3_DPLL_J_TYPE_CLOCK: + case TI_AM3_DPLL_NO_GATE_J_TYPE_CLOCK: + case TI_AM3_DPLL_CLOCK: + case TI_AM3_DPLL_CORE_CLOCK: + case TI_AM3_DPLL_X2_CLOCK: + if (num_regs != 3) + return (ENXIO); + sc->dpll_def.ti_clkmode_offset = reg_cells[0]; + sc->dpll_def.ti_idlest_offset = reg_cells[1]; + sc->dpll_def.ti_clksel_offset = reg_cells[2]; + break; + + case TI_OMAP2_DPLL_CORE_CLOCK: + if (num_regs != 2) + return (ENXIO); + sc->dpll_def.ti_clkmode_offset = reg_cells[0]; + sc->dpll_def.ti_clksel_offset = reg_cells[1]; + break; + + default: + sc->dpll_def.ti_clkmode_offset = reg_cells[0]; + sc->dpll_def.ti_idlest_offset = reg_cells[1]; + sc->dpll_def.ti_clksel_offset = reg_cells[2]; + sc->dpll_def.ti_autoidle_offset = reg_cells[3]; + break; + } + + /* AM335x */ + if (sc->dpll_def.ti_clksel_offset == CM_CLKSEL_DPLL_PERIPH) { + sc->dpll_def.ti_clksel_mult.shift = 8; + sc->dpll_def.ti_clksel_mult.mask = 0x000FFF00; + sc->dpll_def.ti_clksel_mult.width = 12; + sc->dpll_def.ti_clksel_mult.value = 0; + sc->dpll_def.ti_clksel_mult.min_value = 2; + sc->dpll_def.ti_clksel_mult.max_value = 4095; + sc->dpll_def.ti_clksel_mult.flags = TI_CLK_FACTOR_ZERO_BASED | + TI_CLK_FACTOR_MIN_VALUE | + TI_CLK_FACTOR_MAX_VALUE; + + sc->dpll_def.ti_clksel_div.shift = 0; + sc->dpll_def.ti_clksel_div.mask = 0x000000FF; + sc->dpll_def.ti_clksel_div.width = 8; + sc->dpll_def.ti_clksel_div.value = 0; + sc->dpll_def.ti_clksel_div.min_value = 0; + sc->dpll_def.ti_clksel_div.max_value = 255; + sc->dpll_def.ti_clksel_div.flags = TI_CLK_FACTOR_MIN_VALUE | + TI_CLK_FACTOR_MAX_VALUE; + } else { + sc->dpll_def.ti_clksel_mult.shift = 8; + sc->dpll_def.ti_clksel_mult.mask = 0x0007FF00; + sc->dpll_def.ti_clksel_mult.width = 11; + sc->dpll_def.ti_clksel_mult.value = 0; + sc->dpll_def.ti_clksel_mult.min_value = 2; + sc->dpll_def.ti_clksel_mult.max_value = 2047; + sc->dpll_def.ti_clksel_mult.flags = TI_CLK_FACTOR_ZERO_BASED | + TI_CLK_FACTOR_MIN_VALUE | + TI_CLK_FACTOR_MAX_VALUE; + + sc->dpll_def.ti_clksel_div.shift = 0; + sc->dpll_def.ti_clksel_div.mask = 0x0000007F; + sc->dpll_def.ti_clksel_div.width = 7; + sc->dpll_def.ti_clksel_div.value = 0; + sc->dpll_def.ti_clksel_div.min_value = 0; + sc->dpll_def.ti_clksel_div.max_value = 127; + sc->dpll_def.ti_clksel_div.flags = TI_CLK_FACTOR_MIN_VALUE | + TI_CLK_FACTOR_MAX_VALUE; + } + DPRINTF(sc->dev, "clkmode %x idlest %x clksel %x autoidle %x\n", + sc->dpll_def.ti_clkmode_offset, sc->dpll_def.ti_idlest_offset, + sc->dpll_def.ti_clksel_offset, + sc->dpll_def.ti_autoidle_offset); + + return (0); +} +static int +ti_dpll_attach(device_t dev) +{ + struct ti_dpll_softc *sc; + phandle_t node; + int err; + + sc = device_get_softc(dev); + sc->dev = dev; + + sc->dpll_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + node = ofw_bus_get_node(dev); + + /* Grab the content of reg properties */ + parse_dpll_reg(sc); + + /* default flags (OMAP4&AM335x) not present in the dts at moment */ + sc->dpll_def.ti_clkmode_flags = MN_BYPASS_MODE_FLAG | LOCK_MODE_FLAG; + + if (OF_hasprop(node, "ti,low-power-stop")) { + sc->dpll_def.ti_clkmode_flags |= LOW_POWER_STOP_MODE_FLAG; + } + if (OF_hasprop(node, "ti,low-power-bypass")) { + sc->dpll_def.ti_clkmode_flags |= IDLE_BYPASS_LOW_POWER_MODE_FLAG; + } + if (OF_hasprop(node, "ti,lock")) { + sc->dpll_def.ti_clkmode_flags |= LOCK_MODE_FLAG; + } + + read_clock_cells(sc->dev, &sc->clock_cell); + + create_clkdef(sc->dev, &sc->clock_cell, &sc->dpll_def.clkdef); + + err = find_parent_clock_names(sc->dev, &sc->clock_cell, + &sc->dpll_def.clkdef); + + if (err) { + /* free_clkdef will be called in ti_dpll_new_pass */ + DPRINTF(sc->dev, "find_parent_clock_names failed\n"); + return (bus_generic_attach(sc->dev)); + } + + err = register_clk(sc); + + if (err) { + /* free_clkdef will be called in ti_dpll_new_pass */ + DPRINTF(sc->dev, "register_clk failed\n"); + return (bus_generic_attach(sc->dev)); + } + + sc->attach_done = true; + + free_clkdef(&sc->dpll_def.clkdef); + + return (bus_generic_attach(sc->dev)); +} + +static int +ti_dpll_detach(device_t dev) +{ + return (EBUSY); +} + +static void +ti_dpll_new_pass(device_t dev) +{ + struct ti_dpll_softc *sc; + int err; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + return; + } + + err = find_parent_clock_names(sc->dev, &sc->clock_cell, + &sc->dpll_def.clkdef); + if (err) { + /* free_clkdef will be called in a later call to ti_dpll_new_pass */ + DPRINTF(sc->dev, + "new_pass find_parent_clock_names failed\n"); + return; + } + + err = register_clk(sc); + if (err) { + /* free_clkdef will be called in a later call to ti_dpll_new_pass */ + DPRINTF(sc->dev, "new_pass register_clk failed\n"); + return; + } + + sc->attach_done = true; + free_clkdef(&sc->dpll_def.clkdef); +} + +static device_method_t ti_dpll_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_dpll_probe), + DEVMETHOD(device_attach, ti_dpll_attach), + DEVMETHOD(device_detach, ti_dpll_detach), + + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_dpll_new_pass), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_dpll, ti_dpll_driver, ti_dpll_methods, + sizeof(struct ti_dpll_softc)); + +static devclass_t ti_dpll_devclass; + +EARLY_DRIVER_MODULE(ti_dpll, simplebus, ti_dpll_driver, + ti_dpll_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_dpll, 1); Index: head/sys/arm/ti/clk/ti_gate_clock.c =================================================================== --- head/sys/arm/ti/clk/ti_gate_clock.c +++ head/sys/arm/ti/clk/ti_gate_clock.c @@ -0,0 +1,266 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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 + +#include "clock_common.h" + +#define DEBUG_GATE 0 + +#if DEBUG_GATE +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * Devicetree description + * Documentation/devicetree/bindings/clock/ti/gate.txt + */ + +struct ti_gate_softc { + device_t sc_dev; + bool attach_done; + uint8_t sc_type; + + struct clk_gate_def gate_def; + struct clock_cell_info clock_cell; + struct clkdom *clkdom; +}; + +static int ti_gate_probe(device_t dev); +static int ti_gate_attach(device_t dev); +static int ti_gate_detach(device_t dev); + +#define TI_GATE_CLOCK 7 +#define TI_WAIT_GATE_CLOCK 6 +#define TI_DSS_GATE_CLOCK 5 +#define TI_AM35XX_GATE_CLOCK 4 +#define TI_CLKDM_GATE_CLOCK 3 +#define TI_HSDIV_GATE_CLOCK 2 +#define TI_COMPOSITE_NO_WAIT_GATE_CLOCK 1 +#define TI_GATE_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,gate-clock", TI_GATE_CLOCK }, + { "ti,wait-gate-clock", TI_WAIT_GATE_CLOCK }, + { "ti,dss-gate-clock", TI_DSS_GATE_CLOCK }, + { "ti,am35xx-gate-clock", TI_AM35XX_GATE_CLOCK }, + { "ti,clkdm-gate-clock", TI_CLKDM_GATE_CLOCK }, + { "ti,hsdiv-gate-cloc", TI_HSDIV_GATE_CLOCK }, + { "ti,composite-no-wait-gate-clock", TI_COMPOSITE_NO_WAIT_GATE_CLOCK }, + { NULL, TI_GATE_END } +}; + +static int +ti_gate_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI Gate Clock"); + + return (BUS_PROBE_DEFAULT); +} + +static int +register_clk(struct ti_gate_softc *sc) { + int err; + sc->clkdom = clkdom_create(sc->sc_dev); + if (sc->clkdom == NULL) { + DPRINTF(sc->sc_dev, "Failed to create clkdom\n"); + return ENXIO; + } + + err = clknode_gate_register(sc->clkdom, &sc->gate_def); + if (err) { + DPRINTF(sc->sc_dev, "clknode_gate_register failed %x\n", err); + return ENXIO; + } + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->sc_dev, "Clk domain finit fails %x.\n", err); + return ENXIO; + } + + return (0); +} + +static int +ti_gate_attach(device_t dev) +{ + struct ti_gate_softc *sc; + phandle_t node; + int err; + cell_t value; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + node = ofw_bus_get_node(dev); + + /* Get the compatible type */ + sc->sc_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + + /* Get the content of reg properties */ + if (sc->sc_type != TI_CLKDM_GATE_CLOCK) { + OF_getencprop(node, "reg", &value, sizeof(value)); + sc->gate_def.offset = value; + } +#if DEBUG_GATE + else { + DPRINTF(sc->sc_dev, "no reg (TI_CLKDM_GATE_CLOCK)\n"); + } +#endif + + if (OF_hasprop(node, "ti,bit-shift")) { + OF_getencprop(node, "ti,bit-shift", &value, sizeof(value)); + sc->gate_def.shift = value; + DPRINTF(sc->sc_dev, "ti,bit-shift => shift %x\n", sc->gate_def.shift); + } + if (OF_hasprop(node, "ti,set-bit-to-disable")) { + sc->gate_def.on_value = 0; + sc->gate_def.off_value = 1; + DPRINTF(sc->sc_dev, + "on_value = 0, off_value = 1 (ti,set-bit-to-disable)\n"); + } else { + sc->gate_def.on_value = 1; + sc->gate_def.off_value = 0; + DPRINTF(sc->sc_dev, "on_value = 1, off_value = 0\n"); + } + + sc->gate_def.gate_flags = 0x0; + + read_clock_cells(sc->sc_dev, &sc->clock_cell); + + create_clkdef(sc->sc_dev, &sc->clock_cell, &sc->gate_def.clkdef); + + /* Calculate mask */ + sc->gate_def.mask = (1 << fls(sc->clock_cell.num_real_clocks)) - 1; + DPRINTF(sc->sc_dev, "num_real_clocks %x gate_def.mask %x\n", + sc->clock_cell.num_real_clocks, sc->gate_def.mask); + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->gate_def.clkdef); + + if (err) { + /* free_clkdef will be called in ti_gate_new_pass */ + DPRINTF(sc->sc_dev, "find_parent_clock_names failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + err = register_clk(sc); + + if (err) { + /* free_clkdef will be called in ti_gate_new_pass */ + DPRINTF(sc->sc_dev, "register_clk failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + sc->attach_done = true; + + free_clkdef(&sc->gate_def.clkdef); + + return (bus_generic_attach(sc->sc_dev)); +} + +static int +ti_gate_detach(device_t dev) +{ + return (EBUSY); +} + +static void +ti_gate_new_pass(device_t dev) { + struct ti_gate_softc *sc; + int err; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + return; + } + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->gate_def.clkdef); + if (err) { + /* free_clkdef will be called in later call to ti_gate_new_pass */ + DPRINTF(sc->sc_dev, "new_pass find_parent_clock_names failed\n"); + return; + } + + err = register_clk(sc); + if (err) { + /* free_clkdef will be called in later call to ti_gate_new_pass */ + DPRINTF(sc->sc_dev, "new_pass register_clk failed\n"); + return; + } + + sc->attach_done = true; + + free_clkdef(&sc->gate_def.clkdef); +} + +static device_method_t ti_gate_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_gate_probe), + DEVMETHOD(device_attach, ti_gate_attach), + DEVMETHOD(device_detach, ti_gate_detach), + + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_gate_new_pass), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_gate, ti_gate_driver, ti_gate_methods, + sizeof(struct ti_gate_softc)); + +static devclass_t ti_gate_devclass; + +EARLY_DRIVER_MODULE(ti_gate, simplebus, ti_gate_driver, + ti_gate_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_gate, 1); Index: head/sys/arm/ti/clk/ti_mux_clock.c =================================================================== --- head/sys/arm/ti/clk/ti_mux_clock.c +++ head/sys/arm/ti/clk/ti_mux_clock.c @@ -0,0 +1,249 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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 +#include +#include + +#include "clock_common.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* + * Devicetree description + * Documentation/devicetree/bindings/clock/ti/mux.txt + */ + +struct ti_mux_softc { + device_t sc_dev; + bool attach_done; + + struct clk_mux_def mux_def; + struct clock_cell_info clock_cell; + struct clkdom *clkdom; +}; + +static int ti_mux_probe(device_t dev); +static int ti_mux_attach(device_t dev); +static int ti_mux_detach(device_t dev); + +#define TI_MUX_CLOCK 2 +#define TI_COMPOSITE_MUX_CLOCK 1 +#define TI_MUX_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,mux-clock", TI_MUX_CLOCK }, + { "ti,composite-mux-clock", TI_COMPOSITE_MUX_CLOCK }, + { NULL, TI_MUX_END } +}; + +static int +ti_mux_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI Mux Clock"); + + return (BUS_PROBE_DEFAULT); +} + +static int +register_clk(struct ti_mux_softc *sc) { + int err; + + sc->clkdom = clkdom_create(sc->sc_dev); + if (sc->clkdom == NULL) { + DPRINTF(sc->sc_dev, "Failed to create clkdom\n"); + return ENXIO; + } + + err = clknode_mux_register(sc->clkdom, &sc->mux_def); + if (err) { + DPRINTF(sc->sc_dev, "clknode_mux_register failed %x\n", err); + return ENXIO; + } + + err = clkdom_finit(sc->clkdom); + if (err) { + DPRINTF(sc->sc_dev, "Clk domain finit fails %x.\n", err); + return ENXIO; + } + + return 0; +} + +static int +ti_mux_attach(device_t dev) +{ + struct ti_mux_softc *sc; + phandle_t node; + int err; + cell_t value; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + node = ofw_bus_get_node(dev); + + /* Grab the content of reg properties */ + OF_getencprop(node, "reg", &value, sizeof(value)); + sc->mux_def.offset = value; + + if (OF_hasprop(node, "ti,bit-shift")) { + OF_getencprop(node, "ti,bit-shift", &value, sizeof(value)); + sc->mux_def.shift = value; + DPRINTF(sc->sc_dev, "ti,bit-shift => shift %x\n", sc->mux_def.shift); + } + if (OF_hasprop(node, "ti,index-starts-at-one")) { + /* FIXME: Add support in dev/extres/clk */ + /*sc->mux_def.mux_flags = ... */ + device_printf(sc->sc_dev, "ti,index-starts-at-one - Not implemented\n"); + } + + if (OF_hasprop(node, "ti,set-rate-parent")) + device_printf(sc->sc_dev, "ti,set-rate-parent - Not implemented\n"); + if (OF_hasprop(node, "ti,latch-bit")) + device_printf(sc->sc_dev, "ti,latch-bit - Not implemented\n"); + + read_clock_cells(sc->sc_dev, &sc->clock_cell); + + create_clkdef(sc->sc_dev, &sc->clock_cell, &sc->mux_def.clkdef); + + /* Figure out the width from ti_max_div */ + if (sc->mux_def.mux_flags) + sc->mux_def.width = fls(sc->clock_cell.num_real_clocks-1); + else + sc->mux_def.width = fls(sc->clock_cell.num_real_clocks); + + DPRINTF(sc->sc_dev, "sc->clock_cell.num_real_clocks %x def.width %x\n", + sc->clock_cell.num_real_clocks, sc->mux_def.width); + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->mux_def.clkdef); + + if (err) { + /* free_clkdef will be called in ti_mux_new_pass */ + DPRINTF(sc->sc_dev, "find_parent_clock_names failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + err = register_clk(sc); + + if (err) { + /* free_clkdef will be called in ti_mux_new_pass */ + DPRINTF(sc->sc_dev, "register_clk failed\n"); + return (bus_generic_attach(sc->sc_dev)); + } + + sc->attach_done = true; + + free_clkdef(&sc->mux_def.clkdef); + + return (bus_generic_attach(sc->sc_dev)); +} + +static void +ti_mux_new_pass(device_t dev) +{ + struct ti_mux_softc *sc; + int err; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + return; + } + + err = find_parent_clock_names(sc->sc_dev, &sc->clock_cell, &sc->mux_def.clkdef); + if (err) { + /* free_clkdef will be called in later call to ti_mux_new_pass */ + DPRINTF(sc->sc_dev, "ti_mux_new_pass find_parent_clock_names failed\n"); + return; + } + + err = register_clk(sc); + if (err) { + /* free_clkdef will be called in later call to ti_mux_new_pass */ + DPRINTF(sc->sc_dev, "ti_mux_new_pass register_clk failed\n"); + return; + } + + sc->attach_done = true; + + free_clkdef(&sc->mux_def.clkdef); +} + +static int +ti_mux_detach(device_t dev) +{ + return (EBUSY); +} + +static device_method_t ti_mux_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_mux_probe), + DEVMETHOD(device_attach, ti_mux_attach), + DEVMETHOD(device_detach, ti_mux_detach), + + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_mux_new_pass), + + DEVMETHOD_END +}; + +DEFINE_CLASS_0(ti_mux, ti_mux_driver, ti_mux_methods, + sizeof(struct ti_mux_softc)); + +static devclass_t ti_mux_devclass; + +EARLY_DRIVER_MODULE(ti_mux, simplebus, ti_mux_driver, + ti_mux_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_mux, 1); Index: head/sys/arm/ti/cpsw/if_cpsw.c =================================================================== --- head/sys/arm/ti/cpsw/if_cpsw.c +++ head/sys/arm/ti/cpsw/if_cpsw.c @@ -74,7 +74,8 @@ #include #include -#include +#include +#include "syscon_if.h" #include #include @@ -1004,6 +1005,8 @@ struct cpswp_softc *sc; uint32_t reg; uint8_t mac_addr[ETHER_ADDR_LEN]; + phandle_t opp_table; + struct syscon *syscon; sc = device_get_softc(dev); sc->dev = dev; @@ -1047,15 +1050,34 @@ IFQ_SET_MAXLEN(&ifp->if_snd, ifp->if_snd.ifq_drv_maxlen); IFQ_SET_READY(&ifp->if_snd); + /* FIXME: For now; Go and kidnap syscon from opp-table */ + /* ti,cpsw actually have an optional syscon reference but only for am33xx?? */ + opp_table = OF_finddevice("/opp-table"); + if (opp_table == -1) { + device_printf(dev, "Cant find /opp-table\n"); + cpswp_detach(dev); + return (ENXIO); + } + if (!OF_hasprop(opp_table, "syscon")) { + device_printf(dev, "/opp-table doesnt have required syscon property\n"); + cpswp_detach(dev); + return (ENXIO); + } + if (syscon_get_by_ofw_property(dev, opp_table, "syscon", &syscon) != 0) { + device_printf(dev, "Failed to get syscon\n"); + cpswp_detach(dev); + return (ENXIO); + } + /* Get high part of MAC address from control module (mac_id[0|1]_hi) */ - ti_scm_reg_read_4(SCM_MAC_ID0_HI + sc->unit * 8, ®); + reg = SYSCON_READ_4(syscon, SCM_MAC_ID0_HI + sc->unit * 8); mac_addr[0] = reg & 0xFF; mac_addr[1] = (reg >> 8) & 0xFF; mac_addr[2] = (reg >> 16) & 0xFF; mac_addr[3] = (reg >> 24) & 0xFF; /* Get low part of MAC address from control module (mac_id[0|1]_lo) */ - ti_scm_reg_read_4(SCM_MAC_ID0_LO + sc->unit * 8, ®); + reg = SYSCON_READ_4(syscon, SCM_MAC_ID0_LO + sc->unit * 8); mac_addr[4] = reg & 0xFF; mac_addr[5] = (reg >> 8) & 0xFF; Index: head/sys/arm/ti/files.ti =================================================================== --- head/sys/arm/ti/files.ti +++ head/sys/arm/ti/files.ti @@ -1,14 +1,16 @@ #$FreeBSD$ 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_omap4_cm.c standard arm/ti/ti_scm.c standard +arm/ti/ti_scm_syscon.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_prm.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 @@ -17,6 +19,15 @@ arm/ti/ti_sdhci.c optional sdhci arm/ti/ti_spi.c optional ti_spi arm/ti/ti_sysc.c standard + +arm/ti/clk/clock_common.c standard +arm/ti/clk/ti_clk_clkctrl.c standard +arm/ti/clk/ti_clkctrl.c standard +arm/ti/clk/ti_clk_dpll.c standard +arm/ti/clk/ti_dpll_clock.c standard +arm/ti/clk/ti_mux_clock.c standard +arm/ti/clk/ti_divider_clock.c standard +arm/ti/clk/ti_gate_clock.c standard dev/uart/uart_dev_ti8250.c optional uart dev/uart/uart_dev_ns8250.c optional uart Index: head/sys/arm/ti/omap4/files.omap4 =================================================================== --- head/sys/arm/ti/omap4/files.omap4 +++ head/sys/arm/ti/omap4/files.omap4 @@ -9,7 +9,7 @@ arm/ti/omap4/omap4_gpio.c optional gpio arm/ti/omap4/omap4_l2cache.c optional pl310 -arm/ti/omap4/omap4_prcm_clks.c standard +#arm/ti/omap4/omap4_prcm_clks.c standard arm/ti/omap4/omap4_scm_padconf.c standard arm/ti/omap4/omap4_mp.c optional smp arm/ti/omap4/omap4_wugen.c standard Index: head/sys/arm/ti/ti_adc.c =================================================================== --- head/sys/arm/ti/ti_adc.c +++ head/sys/arm/ti/ti_adc.c @@ -58,7 +58,7 @@ #include #endif -#include +#include #include #include @@ -824,7 +824,7 @@ } /* Activate the ADC_TSC module. */ - err = ti_prcm_clk_enable(TSC_ADC_CLK); + err = ti_sysc_clock_enable(device_get_parent(dev)); if (err) return (err); @@ -846,7 +846,7 @@ } /* Check the ADC revision. */ - rev = ADC_READ4(sc, ADC_REVISION); + rev = ADC_READ4(sc, ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); device_printf(dev, "scheme: %#x func: %#x rtl: %d rev: %d.%d custom rev: %d\n", (rev & ADC_REV_SCHEME_MSK) >> ADC_REV_SCHEME_SHIFT, @@ -964,6 +964,7 @@ DRIVER_MODULE(ti_adc, simplebus, ti_adc_driver, ti_adc_devclass, 0, 0); MODULE_VERSION(ti_adc, 1); MODULE_DEPEND(ti_adc, simplebus, 1, 1, 1); +MODULE_DEPEND(ti_adc, ti_sysc, 1, 1, 1); #ifdef EVDEV_SUPPORT MODULE_DEPEND(ti_adc, evdev, 1, 1, 1); #endif Index: head/sys/arm/ti/ti_edma3.c =================================================================== --- head/sys/arm/ti/ti_edma3.c +++ head/sys/arm/ti/ti_edma3.c @@ -54,7 +54,7 @@ #include #include -#include +#include #include @@ -181,8 +181,10 @@ return (ENXIO); } + /* FIXME: Require DTS from Linux kernel 5.7 */ + /* FIXME: OK to enable clkctrl here? */ /* Enable Channel Controller */ - ti_prcm_clk_enable(EDMA_TPCC_CLK); + ti_sysc_clock_enable(device_get_parent(dev)); reg = ti_edma3_cc_rd_4(TI_EDMA3CC_PID); @@ -218,7 +220,7 @@ static devclass_t ti_edma3_devclass; DRIVER_MODULE(ti_edma3, simplebus, ti_edma3_driver, ti_edma3_devclass, 0, 0); -MODULE_DEPEND(ti_edma3, ti_prcm, 1, 1, 1); +MODULE_DEPEND(ti_edma3, ti_sysc, 1, 1, 1); static void ti_edma3_intr_comp(void *arg) @@ -243,11 +245,6 @@ { uint32_t reg; int i; - - /* on AM335x Event queue 0 is always mapped to Transfer Controller 0, - * event queue 1 to TC2, etc. So we are asking PRCM to power on specific - * TC based on what event queue we need to initialize */ - ti_prcm_clk_enable(EDMA_TPTC0_CLK + eqn); /* Clear Event Missed Regs */ ti_edma3_cc_wr_4(TI_EDMA3CC_EMCR, 0xFFFFFFFF); Index: head/sys/arm/ti/ti_gpio.c =================================================================== --- head/sys/arm/ti/ti_gpio.c +++ head/sys/arm/ti/ti_gpio.c @@ -57,8 +57,7 @@ #include #include #include -#include -#include +#include #include #include @@ -117,6 +116,18 @@ #define PINS_PER_BANK 32 #define TI_GPIO_MASK(p) (1U << ((p) % PINS_PER_BANK)) +#define OMAP4_GPIO1_REV 0x00000 +#define OMAP4_GPIO2_REV 0x55000 +#define OMAP4_GPIO3_REV 0x57000 +#define OMAP4_GPIO4_REV 0x59000 +#define OMAP4_GPIO5_REV 0x5b000 +#define OMAP4_GPIO6_REV 0x5d000 + +#define AM335X_GPIO0_REV 0x07000 +#define AM335X_GPIO1_REV 0x4C000 +#define AM335X_GPIO2_REV 0xAC000 +#define AM335X_GPIO3_REV 0xAE000 + static int ti_gpio_intr(void *arg); static int ti_gpio_detach(device_t); @@ -434,7 +445,7 @@ oe &= ~TI_GPIO_MASK(pin); ti_gpio_write_4(sc, TI_GPIO_OE, oe); TI_GPIO_UNLOCK(sc); - + return (0); } @@ -499,7 +510,7 @@ return (EINVAL); /* - * Return data from output latch when set as output and from the + * Return data from output latch when set as output and from the * input register otherwise. */ TI_GPIO_LOCK(sc); @@ -553,29 +564,72 @@ static int ti_gpio_bank_init(device_t dev) { - int pin; + int pin, err; struct ti_gpio_softc *sc; uint32_t flags, reg_oe, reg_set, rev; - clk_ident_t clk; + uint64_t rev_address; sc = device_get_softc(dev); /* Enable the interface and functional clocks for the module. */ - clk = ti_hwmods_get_clock(dev); - if (clk == INVALID_CLK_IDENT) { - device_printf(dev, "failed to get device id based on ti,hwmods\n"); + rev_address = ti_sysc_get_rev_address(device_get_parent(dev)); + /* AM335x + * sc->sc_bank used in am335x/am335x_gpio.c and omap4/omap4_gpio.c */ + switch(ti_chip()) { +#ifdef SOC_OMAP4 + case CHIP_OMAP_4: + switch (rev_address) { + case OMAP4_GPIO1_REV: + sc->sc_bank = 0; + break; + case OMAP4_GPIO2_REV: + sc->sc_bank = 1; + break; + case OMAP4_GPIO3_REV: + sc->sc_bank = 2; + break; + case OMAP4_GPIO4_REV: + sc->sc_bank = 3; + break; + case OMAP4_GPIO5_REV: + sc->sc_bank = 4; + break; + case OMAP4_GPIO6_REV: + sc->sc_bank = 5; + break; + } +#endif +#ifdef SOC_TI_AM335X + case CHIP_AM335X: + switch (rev_address) { + case AM335X_GPIO0_REV: + sc->sc_bank = 0; + break; + case AM335X_GPIO1_REV: + sc->sc_bank = 1; + break; + case AM335X_GPIO2_REV: + sc->sc_bank = 2; + break; + case AM335X_GPIO3_REV: + sc->sc_bank = 3; + break; + } +#endif + } + err = ti_sysc_clock_enable(device_get_parent(dev)); + if (err) { + device_printf(dev, "Failed to enable clock\n"); return (EINVAL); } - sc->sc_bank = clk - GPIO1_CLK + ti_first_gpio_bank(); - ti_prcm_clk_enable(clk); - /* * Read the revision number of the module. TI don't publish the * actual revision numbers, so instead the values have been * determined by experimentation. */ - rev = ti_gpio_read_4(sc, TI_GPIO_REVISION); + rev = ti_gpio_read_4(sc, + ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); /* Check the revision. */ if (rev != ti_gpio_rev()) { @@ -669,7 +723,7 @@ /* We need to go through each block and ensure the clocks are running and * the module is enabled. It might be better to do this only when the * pins are configured which would result in less power used if the GPIO - * pins weren't used ... + * pins weren't used ... */ if (sc->sc_mem_res != NULL) { /* Initialize the GPIO module. */ Index: head/sys/arm/ti/ti_hwmods.h =================================================================== --- head/sys/arm/ti/ti_hwmods.h +++ head/sys/arm/ti/ti_hwmods.h @@ -1,37 +0,0 @@ -/*- - * 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$ - */ -#ifndef _TI_HWMODS_H_ -#define _TI_HWMODS_H_ - -clk_ident_t ti_hwmods_get_clock(device_t dev); -int ti_hwmods_contains(device_t dev, const char *hwmod); - -/* Returns the N from "hwmodN" in the ti,hwmods property; 0 on failure. */ -int ti_hwmods_get_unit(device_t dev, const char *hwmod); - -#endif /* _TI_HWMODS_H_ */ Index: head/sys/arm/ti/ti_hwmods.c =================================================================== --- head/sys/arm/ti/ti_hwmods.c +++ head/sys/arm/ti/ti_hwmods.c @@ -1,214 +0,0 @@ -/*- - * 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 - -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} -}; - -static inline int -ti_get_hwmods_prop(phandle_t node, void **name) -{ - int len; - - if ((len = OF_getprop_alloc(node, "ti,hwmods", name)) > 0) - return (len); - return (OF_getprop_alloc(OF_parent(node), "ti,hwmods", name)); -} - -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 = ti_get_hwmods_prop(node, (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"); - - OF_prop_free(buf); - 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 = ti_get_hwmods_prop(node, (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; - } - - OF_prop_free(buf); - - 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 = ti_get_hwmods_prop(node, (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; - } - - OF_prop_free(buf); - return (result); -} Index: head/sys/arm/ti/ti_i2c.c =================================================================== --- head/sys/arm/ti/ti_i2c.c +++ head/sys/arm/ti/ti_i2c.c @@ -63,8 +63,7 @@ #include #include -#include -#include +#include #include #include @@ -79,7 +78,6 @@ struct ti_i2c_softc { device_t sc_dev; - clk_ident_t clk_id; struct resource* sc_irq_res; struct resource* sc_mem_res; device_t sc_iicbus; @@ -700,7 +698,7 @@ * 1. Enable the functional and interface clocks (see Section * 23.1.5.1.1.1.1). */ - err = ti_prcm_clk_enable(sc->clk_id); + err = ti_sysc_clock_enable(device_get_parent(dev)); if (err) return (err); @@ -748,7 +746,7 @@ } /* Finally disable the functional and interface clocks. */ - ti_prcm_clk_disable(sc->clk_id); + ti_sysc_clock_disable(device_get_parent(dev)); } static int @@ -818,7 +816,6 @@ ti_i2c_attach(device_t dev) { int err, rid; - phandle_t node; struct ti_i2c_softc *sc; struct sysctl_ctx_list *ctx; struct sysctl_oid_list *tree; @@ -827,15 +824,6 @@ sc = device_get_softc(dev); sc->sc_dev = dev; - /* Get the i2c device id from FDT. */ - node = ofw_bus_get_node(dev); - /* i2c ti,hwmods bindings is special: it start with index 1 */ - sc->clk_id = ti_hwmods_get_clock(dev); - if (sc->clk_id == INVALID_CLK_IDENT) { - device_printf(dev, "failed to get device id using ti,hwmod\n"); - return (ENXIO); - } - /* Get the memory resource for the register mapping. */ rid = 0; sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, @@ -986,5 +974,5 @@ DRIVER_MODULE(ti_iic, simplebus, ti_i2c_driver, ti_i2c_devclass, 0, 0); DRIVER_MODULE(iicbus, ti_iic, iicbus_driver, iicbus_devclass, 0, 0); -MODULE_DEPEND(ti_iic, ti_prcm, 1, 1, 1); +MODULE_DEPEND(ti_iic, ti_sysc, 1, 1, 1); MODULE_DEPEND(ti_iic, iicbus, 1, 1, 1); Index: head/sys/arm/ti/ti_mbox.c =================================================================== --- head/sys/arm/ti/ti_mbox.c +++ head/sys/arm/ti/ti_mbox.c @@ -50,7 +50,7 @@ #include #include -#include +#include #include "mbox_if.h" @@ -102,6 +102,7 @@ static devclass_t ti_mbox_devclass; DRIVER_MODULE(ti_mbox, simplebus, ti_mbox_driver, ti_mbox_devclass, 0, 0); +MODULE_DEPEND(ti_mbox, ti_sysc, 1, 1, 1); static __inline uint32_t ti_mbox_reg_read(struct ti_mbox_softc *sc, uint16_t reg) @@ -137,10 +138,11 @@ int rid, delay, chan; uint32_t rev, sysconfig; - if (ti_prcm_clk_enable(MAILBOX0_CLK) != 0) { + if (ti_sysc_clock_enable(device_get_parent(dev)) != 0) { device_printf(dev, "could not enable MBOX clock\n"); return (ENXIO); } + sc = device_get_softc(dev); rid = 0; mtx_init(&sc->sc_mtx, "TI mbox", NULL, MTX_DEF); @@ -188,7 +190,8 @@ */ ti_mbox_reg_write(sc, TI_MBOX_SYSCONFIG, ti_mbox_reg_read(sc, TI_MBOX_SYSCONFIG) | TI_MBOX_SYSCONFIG_SMARTIDLE); - rev = ti_mbox_reg_read(sc, TI_MBOX_REVISION); + rev = ti_mbox_reg_read(sc, + ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); DPRINTF("rev %d\n", rev); device_printf(dev, "revision %d.%d\n", (rev >> 8) & 0x4, rev & 0x40); /* Index: head/sys/arm/ti/ti_omap4_cm.h =================================================================== --- head/sys/arm/ti/ti_omap4_cm.h +++ head/sys/arm/ti/ti_omap4_cm.h @@ -0,0 +1,34 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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$ + */ +#ifndef __TI_OMAP4_CM__ +#define __TI_OMAP4_CM__ + +uint64_t ti_omap4_cm_get_simplebus_base_host(device_t dev); + +#endif /* __TI_OMAP4_CM__ */ Index: head/sys/arm/ti/ti_omap4_cm.c =================================================================== --- head/sys/arm/ti/ti_omap4_cm.c +++ head/sys/arm/ti/ti_omap4_cm.c @@ -0,0 +1,151 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2019 Emmanuel Vadot + * Copyright (c) 2020 Oskar Holmlund + * + * 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. + * + * Based on sys/arm/ti/ti_sysc.c + * + * $FreeBSD$ + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include + +static struct ofw_compat_data compat_data[] = { + { "ti,omap4-cm", 1 }, + { NULL, 0 } +}; + +struct ti_omap4_cm_softc { + struct simplebus_softc sc; + device_t dev; +}; + +uint64_t +ti_omap4_cm_get_simplebus_base_host(device_t dev) { + struct ti_omap4_cm_softc *sc; + + sc = device_get_softc(dev); + if (sc->sc.nranges == 0) + return (0); + + return (sc->sc.ranges[0].host); +} + +static int ti_omap4_cm_probe(device_t dev); +static int ti_omap4_cm_attach(device_t dev); +static int ti_omap4_cm_detach(device_t dev); + +static int +ti_omap4_cm_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI OMAP4-CM"); + if (!bootverbose) + device_quiet(dev); + + return (BUS_PROBE_DEFAULT); +} + +static int +ti_omap4_cm_attach(device_t dev) +{ + struct ti_omap4_cm_softc *sc; + device_t cdev; + phandle_t node, child; + + sc = device_get_softc(dev); + sc->dev = dev; + node = ofw_bus_get_node(dev); + + simplebus_init(dev, node); + if (simplebus_fill_ranges(node, &sc->sc) < 0) { + device_printf(dev, "could not get ranges\n"); + return (ENXIO); + } + + bus_generic_probe(sc->dev); + + for (child = OF_child(node); child > 0; child = OF_peer(child)) { + cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL); + if (cdev != NULL) + device_probe_and_attach(cdev); + } + + return (bus_generic_attach(dev)); +} + +static int +ti_omap4_cm_detach(device_t dev) +{ + return (EBUSY); +} + +static device_method_t ti_omap4_cm_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, ti_omap4_cm_probe), + DEVMETHOD(device_attach, ti_omap4_cm_attach), + DEVMETHOD(device_detach, ti_omap4_cm_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(ti_omap4_cm, ti_omap4_cm_driver, ti_omap4_cm_methods, + sizeof(struct ti_omap4_cm_softc), simplebus_driver); + +static devclass_t ti_omap4_cm_devclass; + +EARLY_DRIVER_MODULE(ti_omap4_cm, simplebus, ti_omap4_cm_driver, +ti_omap4_cm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); + +EARLY_DRIVER_MODULE(ti_omap4_cm, ofwbus, ti_omap4_cm_driver, +ti_omap4_cm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); + Index: head/sys/arm/ti/ti_pinmux.c =================================================================== --- head/sys/arm/ti/ti_pinmux.c +++ head/sys/arm/ti/ti_pinmux.c @@ -459,3 +459,5 @@ static devclass_t ti_pinmux_devclass; DRIVER_MODULE(ti_pinmux, simplebus, ti_pinmux_driver, ti_pinmux_devclass, 0, 0); +MODULE_VERSION(ti_pinmux, 1); +MODULE_DEPEND(ti_pinmux, ti_scm, 1, 1, 1); Index: head/sys/arm/ti/ti_prcm.h =================================================================== --- head/sys/arm/ti/ti_prcm.h +++ head/sys/arm/ti/ti_prcm.h @@ -1,9 +1,7 @@ /*- - * SPDX-License-Identifier: BSD-4-Clause + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2010 - * Ben Gray . - * All rights reserved. + * Copyright (c) 2020 Oskar Holmlund * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -13,197 +11,29 @@ * 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 + * 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 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. + * 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$ */ +#ifndef __TI_PRCM_H__ +#define __TI_PRCM_H__ -/* - * Texas Instruments - OMAP3xxx series processors - * - * Reference: - * OMAP35x Applications Processor - * Technical Reference Manual - * (omap35xx_techref.pdf) - */ -#ifndef _TI_PRCM_H_ -#define _TI_PRCM_H_ +int ti_prcm_write_4(device_t dev, bus_addr_t addr, uint32_t val); +int ti_prcm_read_4(device_t dev, bus_addr_t addr, uint32_t *val); +int ti_prcm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set); +void ti_prcm_device_lock(device_t dev); +void ti_prcm_device_unlock(device_t dev); -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_ */ +#endif Index: head/sys/arm/ti/ti_prcm.c =================================================================== --- head/sys/arm/ti/ti_prcm.c +++ head/sys/arm/ti/ti_prcm.c @@ -1,10 +1,11 @@ /*- - * SPDX-License-Identifier: BSD-4-Clause + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD * - * Copyright (c) 2010 - * Ben Gray . + * Copyright (c) 2012 Damjan Marion * All rights reserved. * + * Copyright (c) 2020 Oskar Holmlund + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -13,345 +14,332 @@ * 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 + * 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 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. - */ - -/** - * Power, Reset and Clock Management Module + * 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. * - * This is a very simple driver wrapper around the PRCM set of registers in - * the OMAP3 chip. It allows you to turn on and off things like the functional - * and interface clocks to the various on-chip modules. - * + * $FreeBSD$ */ + +/* Based on sys/arm/ti/am335x/am335x_prcm.c */ + #include __FBSDID("$FreeBSD$"); #include #include +#include #include #include -#include -#include +#include #include -#include -#include - +#include +#include +#include #include -#include +#include #include #include #include +#include -/** - * ti_*_clk_devmap - Array of clock devices, should be defined one per SoC - * - * This array is typically defined in one of the targeted *_prcm_clk.c - * files and is specific to the given SoC platform. Each entry in the array - * corresponds to an individual clock device. - */ -extern struct ti_clock_dev ti_omap4_clk_devmap[]; -extern struct ti_clock_dev ti_am335x_clk_devmap[]; +#include -/** - * ti_prcm_clk_dev - returns a pointer to the clock device with given id - * @clk: the ID of the clock device to get - * - * Simply iterates through the clk_devmap global array and returns a pointer - * to the clock device if found. - * - * LOCKING: - * None - * - * RETURNS: - * The pointer to the clock device on success, on failure NULL is returned. - */ -static struct ti_clock_dev * -ti_prcm_clk_dev(clk_ident_t clk) +#include +#include +#include + +#include "clkdev_if.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +struct ti_prcm_softc { + struct simplebus_softc sc_simplebus; + device_t dev; + struct resource * mem_res; + bus_space_tag_t bst; + bus_space_handle_t bsh; + int attach_done; + struct mtx mtx; +}; + +static struct ti_prcm_softc *ti_prcm_sc = NULL; +static void omap4_prcm_reset(void); +static void am335x_prcm_reset(void); + +#define TI_AM3_PRCM 18 +#define TI_AM4_PRCM 17 +#define TI_OMAP2_PRCM 16 +#define TI_OMAP3_PRM 15 +#define TI_OMAP3_CM 14 +#define TI_OMAP4_CM1 13 +#define TI_OMAP4_PRM 12 +#define TI_OMAP4_CM2 11 +#define TI_OMAP4_SCRM 10 +#define TI_OMAP5_PRM 9 +#define TI_OMAP5_CM_CORE_AON 8 +#define TI_OMAP5_SCRM 7 +#define TI_OMAP5_CM_CORE 6 +#define TI_DRA7_PRM 5 +#define TI_DRA7_CM_CORE_AON 4 +#define TI_DRA7_CM_CORE 3 +#define TI_DM814_PRCM 2 +#define TI_DM816_PRCM 1 +#define TI_PRCM_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,am3-prcm", TI_AM3_PRCM }, + { "ti,am4-prcm", TI_AM4_PRCM }, + { "ti,omap2-prcm", TI_OMAP2_PRCM }, + { "ti,omap3-prm", TI_OMAP3_PRM }, + { "ti,omap3-cm", TI_OMAP3_CM }, + { "ti,omap4-cm1", TI_OMAP4_CM1 }, + { "ti,omap4-prm", TI_OMAP4_PRM }, + { "ti,omap4-cm2", TI_OMAP4_CM2 }, + { "ti,omap4-scrm", TI_OMAP4_SCRM }, + { "ti,omap5-prm", TI_OMAP5_PRM }, + { "ti,omap5-cm-core-aon", TI_OMAP5_CM_CORE_AON }, + { "ti,omap5-scrm", TI_OMAP5_SCRM }, + { "ti,omap5-cm-core", TI_OMAP5_CM_CORE }, + { "ti,dra7-prm", TI_DRA7_PRM }, + { "ti,dra7-cm-core-aon", TI_DRA7_CM_CORE_AON }, + { "ti,dra7-cm-core", TI_DRA7_CM_CORE }, + { "ti,dm814-prcm", TI_DM814_PRCM }, + { "ti,dm816-prcm", TI_DM816_PRCM }, + { NULL, TI_PRCM_END} +}; + +static int +ti_prcm_probe(device_t dev) { - struct ti_clock_dev *clk_dev; - - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) { + return (ENXIO); + } + + device_set_desc(dev, "TI Power and Clock Management"); + return(BUS_PROBE_DEFAULT); +} + +static int +ti_prcm_attach(device_t dev) +{ + struct ti_prcm_softc *sc; + phandle_t node, child; + int rid; + + sc = device_get_softc(dev); + sc->dev = dev; + + node = ofw_bus_get_node(sc->dev); + simplebus_init(sc->dev, node); + + if (simplebus_fill_ranges(node, &sc->sc_simplebus) < 0) { + device_printf(sc->dev, "could not get ranges\n"); + return (ENXIO); + } + if (sc->sc_simplebus.nranges == 0) { + device_printf(sc->dev, "nranges == 0\n"); + return (ENXIO); + } + + sc->mem_res = bus_alloc_resource(sc->dev, SYS_RES_MEMORY, &rid, + sc->sc_simplebus.ranges[0].host, + (sc->sc_simplebus.ranges[0].host + + sc->sc_simplebus.ranges[0].size - 1), + sc->sc_simplebus.ranges[0].size, + RF_ACTIVE | RF_SHAREABLE); + + if (sc->mem_res == NULL) { + return (ENXIO); + } + + sc->bst = rman_get_bustag(sc->mem_res); + sc->bsh = rman_get_bushandle(sc->mem_res); + + mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF); + + /* Fixme: for xxx_prcm_reset functions. + * Get rid of global variables? */ - clk_dev = NULL; + ti_prcm_sc = sc; + switch(ti_chip()) { #ifdef SOC_OMAP4 case CHIP_OMAP_4: - clk_dev = &(ti_omap4_clk_devmap[0]); + ti_cpu_reset = omap4_prcm_reset; break; #endif #ifdef SOC_TI_AM335X case CHIP_AM335X: - clk_dev = &(ti_am335x_clk_devmap[0]); + ti_cpu_reset = am335x_prcm_reset; break; #endif } - if (clk_dev == NULL) - panic("No clock devmap found"); - while (clk_dev->id != INVALID_CLK_IDENT) { - if (clk_dev->id == clk) { - return (clk_dev); - } - clk_dev++; + + bus_generic_probe(sc->dev); + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + simplebus_add_device(dev, child, 0, NULL, -1, NULL); } - /* Sanity check we managed to find the clock */ - printf("ti_prcm: Failed to find clock device (%d)\n", clk); - return (NULL); + return (bus_generic_attach(sc->dev)); } -/** - * ti_prcm_clk_valid - enables a clock for a particular module - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. - * - * This function can enable either a functional or interface clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ int -ti_prcm_clk_valid(clk_ident_t clk) +ti_prcm_write_4(device_t dev, bus_addr_t addr, uint32_t val) { - int ret = 0; + struct ti_prcm_softc *sc; - if (ti_prcm_clk_dev(clk) == NULL) - ret = EINVAL; - - return (ret); + sc = device_get_softc(dev); + DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val); + bus_space_write_4(sc->bst, sc->bsh, addr, val); + return (0); } - - -/** - * ti_prcm_clk_enable - enables a clock for a particular module - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. - * - * This function can enable either a functional or interface clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ int -ti_prcm_clk_enable(clk_ident_t clk) +ti_prcm_read_4(device_t dev, bus_addr_t addr, uint32_t *val) { - struct ti_clock_dev *clk_dev; - int ret; + struct ti_prcm_softc *sc; - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. - */ - clk_dev = ti_prcm_clk_dev(clk); + sc = device_get_softc(dev); - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); - - /* Activate the clock */ - if (clk_dev->clk_activate) - ret = clk_dev->clk_activate(clk_dev); - else - ret = EINVAL; - - return (ret); + *val = bus_space_read_4(sc->bst, sc->bsh, addr); + DPRINTF(sc->dev, "offset=%lx Read %x\n", addr, *val); + return (0); } - -/** - * ti_prcm_clk_disable - disables a clock for a particular module - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. - * - * This function can enable either a functional or interface clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ int -ti_prcm_clk_disable(clk_ident_t clk) +ti_prcm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) { - struct ti_clock_dev *clk_dev; - int ret; + struct ti_prcm_softc *sc; + uint32_t reg; - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. - */ - clk_dev = ti_prcm_clk_dev(clk); + sc = device_get_softc(dev); - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); + reg = bus_space_read_4(sc->bst, sc->bsh, addr); + reg &= ~clr; + reg |= set; + bus_space_write_4(sc->bst, sc->bsh, addr, reg); + DPRINTF(sc->dev, "offset=%lx reg: %x (clr %x set %x)\n", addr, reg, clr, set); - /* Activate the clock */ - if (clk_dev->clk_deactivate) - ret = clk_dev->clk_deactivate(clk_dev); - else - ret = EINVAL; - - return (ret); + return (0); } -/** - * ti_prcm_clk_set_source - sets the source - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. - * - * This function can enable either a functional or interface clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ -int -ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc) +void +ti_prcm_device_lock(device_t dev) { - struct ti_clock_dev *clk_dev; - int ret; + struct ti_prcm_softc *sc; - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. - */ - clk_dev = ti_prcm_clk_dev(clk); + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); +} - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); +void +ti_prcm_device_unlock(device_t dev) +{ + struct ti_prcm_softc *sc; - /* Activate the clock */ - if (clk_dev->clk_set_source) - ret = clk_dev->clk_set_source(clk_dev, clksrc); - else - ret = EINVAL; - - return (ret); + sc = device_get_softc(dev); + mtx_unlock(&sc->mtx); } +static device_method_t ti_prcm_methods[] = { + DEVMETHOD(device_probe, ti_prcm_probe), + DEVMETHOD(device_attach, ti_prcm_attach), -/** - * ti_prcm_clk_get_source_freq - gets the source clock frequency - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * @freq: pointer to an integer that upon return will contain the src freq - * - * This function returns the frequency of the source clock. - * - * The real work done to enable the clock is really done in the callback - * function associated with the clock, this function is simply a wrapper - * around that. - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ -int -ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq) -{ - struct ti_clock_dev *clk_dev; - int ret; + /* clkdev interface */ + DEVMETHOD(clkdev_write_4, ti_prcm_write_4), + DEVMETHOD(clkdev_read_4, ti_prcm_read_4), + DEVMETHOD(clkdev_modify_4, ti_prcm_modify_4), + DEVMETHOD(clkdev_device_lock, ti_prcm_device_lock), + DEVMETHOD(clkdev_device_unlock, ti_prcm_device_unlock), - /* Find the clock within the devmap - it's a bit inefficent having a for - * loop for this, but this function should only called when a driver is - * being activated so IMHO not a big issue. - */ - clk_dev = ti_prcm_clk_dev(clk); + DEVMETHOD_END +}; - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); +DEFINE_CLASS_1(ti_prcm, ti_prcm_driver, ti_prcm_methods, + sizeof(struct ti_prcm_softc), simplebus_driver); - /* Get the source frequency of the clock */ - if (clk_dev->clk_get_source_freq) - ret = clk_dev->clk_get_source_freq(clk_dev, freq); - else - ret = EINVAL; +static devclass_t ti_prcm_devclass; - return (ret); +EARLY_DRIVER_MODULE(ti_prcm, ofwbus, ti_prcm_driver, + ti_prcm_devclass, 0, 0, BUS_PASS_BUS); +EARLY_DRIVER_MODULE(ti_prcm, simplebus, ti_prcm_driver, + ti_prcm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_prcm, 1); +MODULE_DEPEND(ti_prcm, ti_scm, 1, 1, 1); + + +/* From sys/arm/ti/am335x/am335x_prcm.c + * Copyright (c) 2012 Damjan Marion + */ +#define PRM_DEVICE_OFFSET 0xF00 +#define AM335x_PRM_RSTCTRL (PRM_DEVICE_OFFSET + 0x00) + +static void +am335x_prcm_reset(void) +{ + ti_prcm_write_4(ti_prcm_sc->dev, AM335x_PRM_RSTCTRL, (1<<1)); } -/** - * ti_prcm_clk_set_source_freq - sets the source clock frequency as close to freq as possible - * @clk: identifier for the module to enable, see ti_prcm.h for a list - * of possible modules. - * @freq: requested freq +/* FIXME: Is this correct - or should the license part be ontop? */ + +/* From sys/arm/ti/omap4/omap4_prcm_clks.c */ +/*- + * SPDX-License-Identifier: BSD-3-Clause * - * LOCKING: - * Internally locks the driver context. + * Copyright (c) 2011 + * Ben Gray . + * All rights reserved. * - * RETURNS: - * Returns 0 on success or positive error code on failure. + * 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. */ -int -ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq) +#define PRM_RSTCTRL 0x1b00 +#define PRM_RSTCTRL_RESET 0x2 + +static void +omap4_prcm_reset(void) { - struct ti_clock_dev *clk_dev; - int ret; + uint32_t reg; - clk_dev = ti_prcm_clk_dev(clk); - - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); - - /* Get the source frequency of the clock */ - if (clk_dev->clk_set_source_freq) - ret = clk_dev->clk_set_source_freq(clk_dev, freq); - else - ret = EINVAL; - - return (ret); + ti_prcm_read_4(ti_prcm_sc->dev, PRM_RSTCTRL, ®); + reg = reg | PRM_RSTCTRL_RESET; + ti_prcm_write_4(ti_prcm_sc->dev, PRM_RSTCTRL, reg); + ti_prcm_read_4(ti_prcm_sc->dev, PRM_RSTCTRL, ®); } Index: head/sys/arm/ti/ti_prm.h =================================================================== --- head/sys/arm/ti/ti_prm.h +++ head/sys/arm/ti/ti_prm.h @@ -0,0 +1,38 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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$ + */ +#ifndef __TI_PRM__ +#define __TI_PRM__ + +int ti_prm_reset(device_t dev); + +int ti_prm_write_4(device_t dev, bus_addr_t addr, uint32_t val); +int ti_prm_read_4(device_t dev, bus_addr_t addr, uint32_t *val); +int ti_prm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set); + +#endif /* __TI_PRM__ */ Index: head/sys/arm/ti/ti_prm.c =================================================================== --- head/sys/arm/ti/ti_prm.c +++ head/sys/arm/ti/ti_prm.c @@ -0,0 +1,210 @@ +/*- + * Copyright (c) 2020 Oskar Holmlund + * + * 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$ + */ +/* + * Power management - simple driver to handle reset and give access to + * memory space region for other drivers through prcm driver. + * Documentation/devicetree/binding/arm/omap/prm-inst.txt + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* relative to prcm address range */ +#define TI_PRM_PER_RSTCTRL 0xC00 + +struct ti_prm_softc { + device_t dev; + uint8_t type; + bool has_reset; +}; + +/* Device */ +#define TI_OMAP_PRM_INST 10 + +#define TI_AM3_PRM_INST 5 +#define TI_AM4_PRM_INST 4 +#define TI_OMAP4_PRM_INST 3 +#define TI_OMAP5_PRM_INST 2 +#define TI_DRA7_PRM_INST 1 +#define TI_END 0 + +static struct ofw_compat_data compat_data[] = { + { "ti,am3-prm-inst", TI_AM3_PRM_INST }, + { "ti,am4-prm-inst", TI_AM4_PRM_INST }, + { "ti,omap4-prm-inst", TI_OMAP4_PRM_INST }, + { "ti,omap5-prm-inst", TI_OMAP5_PRM_INST }, + { "ti,dra7-prm-inst", TI_DRA7_PRM_INST }, + { NULL, TI_END } +}; + +static struct ofw_compat_data required_data[] = { + { "ti,omap-prm-inst", TI_OMAP_PRM_INST }, + { NULL, TI_END } +}; + +/* device interface */ +static int +ti_prm_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, required_data)->ocd_data == 0) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI OMAP Power Management"); + return(BUS_PROBE_DEFAULT); +} + +static int +ti_prm_attach(device_t dev) +{ + struct ti_prm_softc *sc; + phandle_t node; + + sc = device_get_softc(dev); + sc->dev = dev; + sc->type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; + + node = ofw_bus_get_node(sc->dev); + + if (OF_hasprop(node, "#reset-cells")) { + sc->has_reset = true; + } else + sc->has_reset = false; + + /* Make device visible for other drivers */ + OF_device_register_xref(OF_xref_from_node(node), sc->dev); + + return (0); +} + +static int +ti_prm_detach(device_t dev) { + return (EBUSY); +} + +int +ti_prm_reset(device_t dev) +{ + struct ti_prm_softc *sc; + int err; + + sc = device_get_softc(dev); + if (sc->has_reset == false) + return 1; + + err = ti_prm_modify_4(dev, TI_PRM_PER_RSTCTRL, 0x2, 0x00); + return (err); +} + +int +ti_prm_write_4(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct ti_prm_softc *sc; + device_t parent; + + parent = device_get_parent(dev); + sc = device_get_softc(dev); + DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val); + ti_prcm_device_lock(parent); + ti_prcm_write_4(parent, addr, val); + ti_prcm_device_unlock(parent); + return (0); +} + +int +ti_prm_read_4(device_t dev, bus_addr_t addr, uint32_t *val) +{ + struct ti_prm_softc *sc; + device_t parent; + + parent = device_get_parent(dev); + sc = device_get_softc(dev); + + ti_prcm_device_lock(parent); + ti_prcm_read_4(parent, addr, val); + ti_prcm_device_unlock(parent); + DPRINTF(sc->dev, "offset=%lx Read %x\n", addr, *val); + return (0); +} + +int +ti_prm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) +{ + struct ti_prm_softc *sc; + device_t parent; + + parent = device_get_parent(dev); + sc = device_get_softc(dev); + + ti_prcm_device_lock(parent); + ti_prcm_modify_4(parent, addr, clr, set); + ti_prcm_device_unlock(parent); + DPRINTF(sc->dev, "offset=%lx (clr %x set %x)\n", addr, clr, set); + + return (0); +} + +static device_method_t ti_prm_methods[] = { + DEVMETHOD(device_probe, ti_prm_probe), + DEVMETHOD(device_attach, ti_prm_attach), + DEVMETHOD(device_detach, ti_prm_detach), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(ti_prm, ti_prm_driver, ti_prm_methods, + sizeof(struct ti_prm_softc), simplebus_driver); + +static devclass_t ti_prm_devclass; + +EARLY_DRIVER_MODULE(ti_prm, simplebus, ti_prm_driver, + ti_prm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_prm, 1); +MODULE_DEPEND(ti_prm, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/ti_pruss.c =================================================================== --- head/sys/arm/ti/ti_pruss.c +++ head/sys/arm/ti/ti_pruss.c @@ -57,8 +57,11 @@ #include #include -#include +#include + +#include #include +#include #ifdef DEBUG #define DPRINTF(fmt, ...) do { \ @@ -161,7 +164,8 @@ static devclass_t ti_pruss_devclass; DRIVER_MODULE(ti_pruss, simplebus, ti_pruss_driver, ti_pruss_devclass, 0, 0); -MODULE_DEPEND(ti_pruss, ti_prcm, 1, 1, 1); +MODULE_DEPEND(ti_pruss, ti_sysc, 1, 1, 1); +MODULE_DEPEND(ti_pruss, ti_prm, 1, 1, 1); static struct resource_spec ti_pruss_irq_spec[] = { { SYS_RES_IRQ, 0, RF_ACTIVE }, @@ -515,14 +519,89 @@ ti_pruss_attach(device_t dev) { struct ti_pruss_softc *sc; - int rid, i; + int rid, i, err, ncells; + uint32_t reg; + phandle_t node; + clk_t l3_gclk, pruss_ocp_gclk; + phandle_t ti_prm_ref, *cells; + device_t ti_prm_dev; - if (ti_prcm_clk_enable(PRUSS_CLK) != 0) { - device_printf(dev, "could not enable PRUSS clock\n"); + rid = 0; + sc = device_get_softc(dev); + node = ofw_bus_get_node(device_get_parent(dev)); + if (node <= 0) { + device_printf(dev, "Cant get ofw node\n"); return (ENXIO); } - sc = device_get_softc(dev); - rid = 0; + + /* + * Follow activate pattern from sys/arm/ti/am335x/am335x_prcm.c + * by Damjan Marion + */ + + /* Set MODULEMODE to ENABLE(2) */ + /* Wait for MODULEMODE to become ENABLE(2) */ + if (ti_sysc_clock_enable(device_get_parent(dev)) != 0) { + device_printf(dev, "Could not enable PRUSS clock\n"); + return (ENXIO); + } + + /* Set CLKTRCTRL to SW_WKUP(2) */ + /* Wait for the 200 MHz OCP clock to become active */ + /* Wait for the 200 MHz IEP clock to become active */ + /* Wait for the 192 MHz UART clock to become active */ + /* + * At the moment there is no reference to CM_PER_PRU_ICSS_CLKSTCTRL@140 + * in the devicetree. The register reset state are SW_WKUP(2) as default + * so at the moment ignore setting this register. + */ + + /* Select L3F as OCP clock */ + /* Get the clock and set the parent */ + err = clk_get_by_name(dev, "l3_gclk", &l3_gclk); + if (err) { + device_printf(dev, "Cant get l3_gclk err %d\n", err); + return (ENXIO); + } + + err = clk_get_by_name(dev, "pruss_ocp_gclk@530", &pruss_ocp_gclk); + if (err) { + device_printf(dev, "Cant get pruss_ocp_gclk@530 err %d\n", err); + return (ENXIO); + } + + err = clk_set_parent_by_clk(pruss_ocp_gclk, l3_gclk); + if (err) { + device_printf(dev, + "Cant set pruss_ocp_gclk parent to l3_gclk err %d\n", err); + return (ENXIO); + } + + /* Clear the RESET bit */ + /* Find the ti_prm */ + /* #reset-cells should not been used in this way but... */ + err = ofw_bus_parse_xref_list_alloc(node, "resets", "#reset-cells", 0, + &ti_prm_ref, &ncells, &cells); + OF_prop_free(cells); + if (err) { + device_printf(dev, + "Cant fetch \"resets\" reference %x\n", err); + return (ENXIO); + } + + ti_prm_dev = OF_device_from_xref(ti_prm_ref); + if (ti_prm_dev == NULL) { + device_printf(dev, "Cant get device from \"resets\"\n"); + return (ENXIO); + } + + err = ti_prm_reset(ti_prm_dev); + if (err) { + device_printf(dev, "ti_prm_reset failed %d\n", err); + return (ENXIO); + } + /* End of clock activation */ + mtx_init(&sc->sc_mtx, "TI PRUSS", NULL, MTX_DEF); sc->sc_mem_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); @@ -601,6 +680,9 @@ knlist_init_mtx(&sc->sc_irq_devs[i].sc_selinfo.si_note, &sc->sc_irq_devs[i].sc_mtx); } } + + reg = ti_pruss_reg_read(sc, + ti_sysc_get_sysc_address_offset_host(device_get_parent(dev))); if (ti_pruss_reg_read(sc, PRUSS_AM33XX_INTC) == PRUSS_AM33XX_REV) device_printf(dev, "AM33xx PRU-ICSS\n"); Index: head/sys/arm/ti/ti_scm.c =================================================================== --- head/sys/arm/ti/ti_scm.c +++ head/sys/arm/ti/ti_scm.c @@ -1,9 +1,7 @@ /*- - * SPDX-License-Identifier: BSD-4-Clause + * Copyright (c) 2019 Emmanuel Vadot * - * Copyright (c) 2010 - * Ben Gray . - * All rights reserved. + * Copyright (c) 2020 Oskar Holmlund * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions @@ -13,169 +11,152 @@ * 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 + * 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 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 + * 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. * - * 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 ti_scm_padconf structs - * call ti_padconf_devmap to be located somewhere in the kernel. - * + * $FreeBSD$ */ + #include __FBSDID("$FreeBSD$"); + +/* Based on sys/arm/ti/ti_sysc.c */ + #include #include +#include +#include #include #include -#include -#include #include -#include -#include - +#include #include -#include +#include +#include +#include +#include -#include +#include + #include #include -#include -#include "ti_scm.h" -#include "ti_cpuid.h" +#define TI_AM3_SCM 14 +#define TI_AM4_SCM 13 +#define TI_DM814_SCRM 12 +#define TI_DM816_SCRM 11 +#define TI_OMAP2_SCM 10 +#define TI_OMAP3_SCM 9 +#define TI_OMAP4_SCM_CORE 8 +#define TI_OMAP4_SCM_PADCONF_CORE 7 +#define TI_OMAP4_SCM_WKUP 6 +#define TI_OMAP4_SCM_PADCONF_WKUP 5 +#define TI_OMAP5_SCM_CORE 4 +#define TI_OMAP5_SCM_PADCONF_CORE 3 +#define TI_OMAP5_SCM_WKUP_PAD_CONF 2 +#define TI_DRA7_SCM_CORE 1 +#define TI_SCM_END 0 -static struct resource_spec ti_scm_res_spec[] = { - { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */ - { -1, 0 } +static struct ofw_compat_data compat_data[] = { + { "ti,am3-scm", TI_AM3_SCM }, + { "ti,am4-scm", TI_AM4_SCM }, + { "ti,dm814-scrm", TI_DM814_SCRM }, + { "ti,dm816-scrm", TI_DM816_SCRM }, + { "ti,omap2-scm", TI_OMAP2_SCM }, + { "ti,omap3-scm", TI_OMAP3_SCM }, + { "ti,omap4-scm-core", TI_OMAP4_SCM_CORE }, + { "ti,omap4-scm-padconf-core", TI_OMAP4_SCM_PADCONF_CORE }, + { "ti,omap4-scm-wkup", TI_OMAP4_SCM_WKUP }, + { "ti,omap4-scm-padconf-wkup", TI_OMAP4_SCM_PADCONF_WKUP }, + { "ti,omap5-scm-core", TI_OMAP5_SCM_CORE }, + { "ti,omap5-scm-padconf-core", TI_OMAP5_SCM_PADCONF_CORE }, + { "ti,omap5-scm-wkup-pad-conf", TI_OMAP5_SCM_WKUP_PAD_CONF }, + { "ti,dra7-scm-core", TI_DRA7_SCM_CORE }, + { NULL, TI_SCM_END } }; -static struct ti_scm_softc *ti_scm_sc; +struct ti_scm_softc { + struct simplebus_softc sc; + device_t dev; +}; -#define ti_scm_read_4(sc, reg) \ - bus_space_read_4((sc)->sc_bst, (sc)->sc_bsh, (reg)) -#define ti_scm_write_4(sc, reg, val) \ - bus_space_write_4((sc)->sc_bst, (sc)->sc_bsh, (reg), (val)) +static int ti_scm_probe(device_t dev); +static int ti_scm_attach(device_t dev); +static int ti_scm_detach(device_t dev); -/* - * Device part of OMAP SCM driver - */ static int ti_scm_probe(device_t dev) { - - if (!ti_soc_is_supported()) - return (ENXIO); - if (!ofw_bus_status_okay(dev)) return (ENXIO); - if (!ofw_bus_is_compatible(dev, "syscon")) + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) return (ENXIO); - if (ti_scm_sc) { - return (EEXIST); - } + device_set_desc(dev, "TI OMAP Control Module"); - device_set_desc(dev, "TI Control Module"); return (BUS_PROBE_DEFAULT); } -/** - * ti_scm_attach - attaches the timer to the simplebus - * @dev: new device - * - * Reserves memory and interrupt resources, stores the softc structure - * globally and registers both the timecount and eventtimer objects. - * - * RETURNS - * Zero on success or ENXIO if an error occuried. - */ static int ti_scm_attach(device_t dev) { - struct ti_scm_softc *sc = device_get_softc(dev); + struct ti_scm_softc *sc; + device_t cdev; + phandle_t node, child; - sc->sc_dev = dev; + sc = device_get_softc(dev); + sc->dev = dev; + node = ofw_bus_get_node(dev); - if (bus_alloc_resources(dev, ti_scm_res_spec, sc->sc_res)) { - device_printf(dev, "could not allocate resources\n"); + simplebus_init(dev, node); + if (simplebus_fill_ranges(node, &sc->sc) < 0) { + device_printf(dev, "could not get ranges\n"); return (ENXIO); } - /* Global timer interface */ - sc->sc_bst = rman_get_bustag(sc->sc_res[0]); - sc->sc_bsh = rman_get_bushandle(sc->sc_res[0]); + for (child = OF_child(node); child > 0; child = OF_peer(child)) { + cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL); + if (cdev != NULL) + device_probe_and_attach(cdev); + } - ti_scm_sc = sc; - - /* Attach platform extensions, if any. */ - bus_generic_probe(dev); - return (bus_generic_attach(dev)); } -int -ti_scm_reg_read_4(uint32_t reg, uint32_t *val) +static int +ti_scm_detach(device_t dev) { - if (!ti_scm_sc) - return (ENXIO); - - *val = ti_scm_read_4(ti_scm_sc, reg); - return (0); + return (EBUSY); } -int -ti_scm_reg_write_4(uint32_t reg, uint32_t val) -{ - if (!ti_scm_sc) - return (ENXIO); - - ti_scm_write_4(ti_scm_sc, reg, val); - return (0); -} - - static device_method_t ti_scm_methods[] = { + /* Device interface */ DEVMETHOD(device_probe, ti_scm_probe), DEVMETHOD(device_attach, ti_scm_attach), + DEVMETHOD(device_detach, ti_scm_detach), - { 0, 0 } + DEVMETHOD_END }; -static driver_t ti_scm_driver = { - "ti_scm", - ti_scm_methods, - sizeof(struct ti_scm_softc), -}; +DEFINE_CLASS_1(ti_scm, ti_scm_driver, ti_scm_methods, + sizeof(struct ti_scm_softc), simplebus_driver); static devclass_t ti_scm_devclass; -EARLY_DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, ti_scm_devclass, 0, 0, - BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +EARLY_DRIVER_MODULE(ti_scm, simplebus, ti_scm_driver, + ti_scm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); +MODULE_VERSION(ti_scm, 1); +MODULE_DEPEND(ti_scm, ti_sysc, 1, 1, 1); + Index: head/sys/arm/ti/ti_scm_syscon.c =================================================================== --- head/sys/arm/ti/ti_scm_syscon.c +++ head/sys/arm/ti/ti_scm_syscon.c @@ -0,0 +1,294 @@ +/*- + * Copyright (c) 2019 Emmanuel Vadot + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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$ + */ +/* Based on sys/arm/ti/ti_sysc.c */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include "syscon_if.h" +#include +#include "clkdev_if.h" + +#if 0 +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +MALLOC_DECLARE(M_SYSCON); + +struct ti_scm_syscon_softc { + struct simplebus_softc sc_simplebus; + device_t dev; + struct syscon * syscon; + struct resource * res[1]; + bus_space_tag_t bst; + bus_space_handle_t bsh; + struct mtx mtx; +}; + +static struct resource_spec ti_scm_syscon_res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE | RF_SHAREABLE }, + { -1, 0 } +}; + +/* Device */ +static struct ofw_compat_data compat_data[] = { + { "syscon", 1 }, + { NULL, 0 } +}; + +/* --- dev/extres/syscon syscon_method_t interface --- */ +static int +ti_scm_syscon_write_4(struct syscon *syscon, bus_size_t offset, uint32_t val) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(syscon->pdev); + DPRINTF(sc->dev, "offset=%lx write %x\n", offset, val); + mtx_lock(&sc->mtx); + bus_space_write_4(sc->bst, sc->bsh, offset, val); + mtx_unlock(&sc->mtx); + return (0); +} + +static uint32_t +ti_scm_syscon_read_4(struct syscon *syscon, bus_size_t offset) +{ + struct ti_scm_syscon_softc *sc; + uint32_t val; + + sc = device_get_softc(syscon->pdev); + + mtx_lock(&sc->mtx); + val = bus_space_read_4(sc->bst, sc->bsh, offset); + mtx_unlock(&sc->mtx); + DPRINTF(sc->dev, "offset=%lx Read %x\n", offset, val); + return (val); +} +static int +ti_scm_syscon_modify_4(struct syscon *syscon, bus_size_t offset, uint32_t clr, uint32_t set) +{ + struct ti_scm_syscon_softc *sc; + uint32_t reg; + + sc = device_get_softc(syscon->pdev); + + mtx_lock(&sc->mtx); + reg = bus_space_read_4(sc->bst, sc->bsh, offset); + reg &= ~clr; + reg |= set; + bus_space_write_4(sc->bst, sc->bsh, offset, reg); + mtx_unlock(&sc->mtx); + DPRINTF(sc->dev, "offset=%lx reg: %x (clr %x set %x)\n", offset, reg, clr, set); + + return (0); +} + +static syscon_method_t ti_scm_syscon_reg_methods[] = { + SYSCONMETHOD(syscon_read_4, ti_scm_syscon_read_4), + SYSCONMETHOD(syscon_write_4, ti_scm_syscon_write_4), + SYSCONMETHOD(syscon_modify_4, ti_scm_syscon_modify_4), + + SYSCONMETHOD_END +}; + +DEFINE_CLASS_1(ti_scm_syscon_reg, ti_scm_syscon_reg_class, ti_scm_syscon_reg_methods, + 0, syscon_class); + +/* device interface */ +static int +ti_scm_syscon_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + device_set_desc(dev, "TI OMAP Control Module Syscon"); + return(BUS_PROBE_DEFAULT); +} + +static int +ti_scm_syscon_attach(device_t dev) +{ + struct ti_scm_syscon_softc *sc; + phandle_t node, child; + int err; + + sc = device_get_softc(dev); + sc->dev = dev; + + if (bus_alloc_resources(dev, ti_scm_syscon_res_spec, sc->res)) { + device_printf(sc->dev, "Cant allocate resources\n"); + return (ENXIO); + } + + sc->dev = dev; + sc->bst = rman_get_bustag(sc->res[0]); + sc->bsh = rman_get_bushandle(sc->res[0]); + + mtx_init(&sc->mtx, device_get_nameunit(sc->dev), NULL, MTX_DEF); + node = ofw_bus_get_node(sc->dev); + + /* dev/extres/syscon interface */ + sc->syscon = syscon_create_ofw_node(dev, &ti_scm_syscon_reg_class, node); + if (sc->syscon == NULL) { + device_printf(dev, "Failed to create/register syscon\n"); + return (ENXIO); + } + + simplebus_init(sc->dev, node); + + err = bus_generic_probe(sc->dev); + for (child = OF_child(node); child != 0; child = OF_peer(child)) { + simplebus_add_device(sc->dev, child, 0, NULL, -1, NULL); + } + + return (bus_generic_attach(sc->dev)); +} + +/* syscon interface */ +static int +ti_scm_syscon_get_handle(device_t dev, struct syscon **syscon) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(dev); + *syscon = sc->syscon; + if (*syscon == NULL) + return (ENODEV); + return (0); +} + +/* clkdev interface */ +static int +ti_scm_syscon_clk_write_4(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(dev); + DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val); + bus_space_write_4(sc->bst, sc->bsh, addr, val); + return (0); +} + +static int +ti_scm_syscon_clk_read_4(device_t dev, bus_addr_t addr, uint32_t *val) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(dev); + + *val = bus_space_read_4(sc->bst, sc->bsh, addr); + DPRINTF(sc->dev, "offset=%lx Read %x\n", addr, *val); + return (0); +} + +static int +ti_scm_syscon_clk_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) +{ + struct ti_scm_syscon_softc *sc; + uint32_t reg; + + sc = device_get_softc(dev); + + reg = bus_space_read_4(sc->bst, sc->bsh, addr); + reg &= ~clr; + reg |= set; + bus_space_write_4(sc->bst, sc->bsh, addr, reg); + DPRINTF(sc->dev, "offset=%lx reg: %x (clr %x set %x)\n", addr, reg, clr, set); + + return (0); +} + +static void +ti_scm_syscon_clk_device_lock(device_t dev) +{ + struct ti_scm_syscon_softc *sc; + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); +} + +static void +ti_scm_syscon_clk_device_unlock(device_t dev) +{ + struct ti_scm_syscon_softc *sc; + sc = device_get_softc(dev); + mtx_unlock(&sc->mtx); +} + +static device_method_t ti_scm_syscon_methods[] = { + DEVMETHOD(device_probe, ti_scm_syscon_probe), + DEVMETHOD(device_attach, ti_scm_syscon_attach), + + /* syscon interface */ + DEVMETHOD(syscon_get_handle, ti_scm_syscon_get_handle), + + /* clkdev interface */ + DEVMETHOD(clkdev_write_4, ti_scm_syscon_clk_write_4), + DEVMETHOD(clkdev_read_4, ti_scm_syscon_clk_read_4), + DEVMETHOD(clkdev_modify_4, ti_scm_syscon_clk_modify_4), + DEVMETHOD(clkdev_device_lock, ti_scm_syscon_clk_device_lock), + DEVMETHOD(clkdev_device_unlock, ti_scm_syscon_clk_device_unlock), + + DEVMETHOD_END +}; + + +DEFINE_CLASS_1(ti_scm_syscon, ti_scm_syscon_driver, ti_scm_syscon_methods, + sizeof(struct ti_scm_syscon_softc), simplebus_driver); + +static devclass_t ti_scm_syscon_devclass; + +EARLY_DRIVER_MODULE(ti_scm_syscon, simplebus, ti_scm_syscon_driver, + ti_scm_syscon_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); +MODULE_VERSION(ti_scm_syscon, 1); +MODULE_DEPEND(ti_scm_syscon, ti_scm, 1, 1, 1); Index: head/sys/arm/ti/ti_sdhci.c =================================================================== --- head/sys/arm/ti/ti_sdhci.c +++ head/sys/arm/ti/ti_sdhci.c @@ -44,10 +44,11 @@ #include #include -#include -#include -#include +#include +#include +#include "gpio_if.h" +#include #include #include @@ -59,11 +60,11 @@ #include #include "sdhci_if.h" -#include -#include -#include -#include "gpio_if.h" +#include +#include +#include + #include "opt_mmccam.h" struct ti_sdhci_softc { @@ -73,10 +74,9 @@ struct resource * irq_res; void * intr_cookie; struct sdhci_slot slot; - clk_ident_t mmchs_clk_id; uint32_t mmchs_reg_off; uint32_t sdhci_reg_off; - uint32_t baseclk_hz; + uint64_t baseclk_hz; uint32_t cmd_and_mode; uint32_t sdhci_clkdiv; boolean_t disable_highspeed; @@ -414,25 +414,33 @@ return (EBUSY); } -static void +static int ti_sdhci_hw_init(device_t dev) { struct ti_sdhci_softc *sc = device_get_softc(dev); uint32_t regval; unsigned long timeout; + clk_t mmc_clk; + int err; /* Enable the controller and interface/functional clocks */ - if (ti_prcm_clk_enable(sc->mmchs_clk_id) != 0) { + if (ti_sysc_clock_enable(device_get_parent(dev)) != 0) { device_printf(dev, "Error: failed to enable MMC clock\n"); - return; + return (ENXIO); } - /* Get the frequency of the source clock */ - if (ti_prcm_clk_get_source_freq(sc->mmchs_clk_id, - &sc->baseclk_hz) != 0) { - device_printf(dev, "Error: failed to get source clock freq\n"); - return; + /* FIXME: Devicetree dosent have any reference to mmc_clk */ + err = clk_get_by_name(dev, "mmc_clk", &mmc_clk); + if (err) { + device_printf(dev, "Can not find mmc_clk\n"); + return (ENXIO); } + err = clk_get_freq(mmc_clk, &sc->baseclk_hz); + if (err) { + device_printf(dev, "Cant get mmc_clk frequency\n"); + /* AM335x TRM 8.1.6.8 table 8-24 96MHz @ OPP100 */ + sc->baseclk_hz = 96000000; + } /* Issue a softreset to the controller */ ti_mmchs_write_4(sc, MMCHS_SYSCONFIG, MMCHS_SYSCONFIG_RESET); @@ -499,6 +507,8 @@ /* Set the initial controller configuration. */ ti_mmchs_write_4(sc, MMCHS_CON, MMCHS_CON_DVAL_8_4MS); + + return (0); } static int @@ -512,16 +522,9 @@ 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. + * Get the MMCHS device id from FDT. Use rev address to identify the unit. */ node = ofw_bus_get_node(dev); - sc->mmchs_clk_id = ti_hwmods_get_clock(dev); - if (sc->mmchs_clk_id == INVALID_CLK_IDENT) { - device_printf(dev, "failed to get clock based on hwmods property\n"); - } /* * The hardware can inherently do dual-voltage (1p8v, 3p0v) on the first @@ -531,7 +534,8 @@ * that it can set the right values in the CAPA register. */ sc->slot.host.caps |= MMC_OCR_LOW_VOLTAGE; - if (sc->mmchs_clk_id == MMC1_CLK || OF_hasprop(node, "ti,dual-volt")) { + + if (OF_hasprop(node, "ti,dual-volt")) { sc->slot.host.caps |= MMC_OCR_290_300 | MMC_OCR_300_310; } @@ -603,7 +607,11 @@ sc->disable_readonly = true; /* Initialise the MMCHS hardware. */ - ti_sdhci_hw_init(dev); + err = ti_sdhci_hw_init(dev); + if (err != 0) { + /* err should already contain ENXIO from ti_sdhci_hw_init() */ + goto fail; + } /* * The capabilities register can only express base clock frequencies in @@ -754,6 +762,7 @@ DRIVER_MODULE(sdhci_ti, simplebus, ti_sdhci_driver, ti_sdhci_devclass, NULL, NULL); +MODULE_DEPEND(sdhci_ti, ti_sysc, 1, 1, 1); SDHCI_DEPEND(sdhci_ti); #ifndef MMCCAM Index: head/sys/arm/ti/ti_sdma.c =================================================================== --- head/sys/arm/ti/ti_sdma.c +++ head/sys/arm/ti/ti_sdma.c @@ -51,7 +51,7 @@ #include #include -#include +#include #include #include @@ -79,7 +79,7 @@ */ struct ti_sdma_channel { - /* + /* * The configuration registers for the given channel, these are modified * by the set functions and only written to the actual registers when a * transaction is started. @@ -109,7 +109,7 @@ struct resource* sc_irq_res; struct resource* sc_mem_res; - /* + /* * I guess in theory we should have a mutex per DMA channel for register * modifications. But since we know we are never going to be run on a SMP * system, we can use just the single lock for all channels. @@ -119,7 +119,7 @@ /* Stores the H/W revision read from the registers */ uint32_t sc_hw_rev; - /* + /* * Bits in the sc_active_channels data field indicate if the channel has * been activated. */ @@ -266,7 +266,7 @@ if (csr & DMA4_CSR_TRANS_ERR) { device_printf(sc->sc_dev, "Transaction error event on " "channel %u\n", ch); - /* + /* * Apparently according to linux code, there is an errata * that says the channel is not disabled upon this error. * They explicitly disable the channel here .. since I @@ -1175,10 +1175,11 @@ panic("%s: Cannot map registers", device_get_name(dev)); /* Enable the interface and functional clocks */ - ti_prcm_clk_enable(SDMA_CLK); + ti_sysc_clock_enable(device_get_parent(dev)); /* Read the sDMA revision register and sanity check it's known */ - sc->sc_hw_rev = ti_sdma_read_4(sc, DMA4_REVISION); + sc->sc_hw_rev = ti_sdma_read_4(sc, + ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); device_printf(dev, "sDMA revision %08x\n", sc->sc_hw_rev); if (!ti_sdma_is_omap4_rev(sc) && !ti_sdma_is_omap3_rev(sc)) { @@ -1213,7 +1214,7 @@ } } - /* + /* * Install interrupt handlers for the for possible interrupts. Any channel * can trip one of the four IRQs */ @@ -1248,4 +1249,4 @@ static devclass_t ti_sdma_devclass; DRIVER_MODULE(ti_sdma, simplebus, ti_sdma_driver, ti_sdma_devclass, 0, 0); -MODULE_DEPEND(ti_sdma, ti_prcm, 1, 1, 1); +MODULE_DEPEND(ti_sdma, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/ti_spi.c =================================================================== --- head/sys/arm/ti/ti_spi.c +++ head/sys/arm/ti/ti_spi.c @@ -48,8 +48,7 @@ #include #include -#include -#include +#include #include #include @@ -166,28 +165,15 @@ static int ti_spi_attach(device_t dev) { - int clk_id, err, i, rid, timeout; + int 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); + err = ti_sysc_clock_enable(device_get_parent(dev)); if (err) { device_printf(dev, "Error: failed to activate source clock\n"); return (err); @@ -245,7 +231,8 @@ } /* Print the McSPI module revision. */ - rev = TI_SPI_READ(sc, MCSPI_REVISION); + rev = TI_SPI_READ(sc, + ti_sysc_get_rev_address_offset_host(device_get_parent(dev))); 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, @@ -592,3 +579,4 @@ }; DRIVER_MODULE(ti_spi, simplebus, ti_spi_driver, ti_spi_devclass, 0, 0); +MODULE_DEPEND(ti_spi, ti_sysc, 1, 1, 1); Index: head/sys/arm/ti/ti_sysc.h =================================================================== --- head/sys/arm/ti/ti_sysc.h +++ head/sys/arm/ti/ti_sysc.h @@ -0,0 +1,43 @@ +/*- + * SPDX-License-Identifier: BSD-2-Clause-FreeBSD + * + * Copyright (c) 2020 Oskar Holmlund + * + * 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$ + */ +#ifndef __TI_SYSC__ +#define __TI_SYSC__ + +uint64_t ti_sysc_get_rev_address(device_t dev); +uint64_t ti_sysc_get_rev_address_offset_host(device_t dev); +uint64_t ti_sysc_get_sysc_address(device_t dev); +uint64_t ti_sysc_get_sysc_address_offset_host(device_t dev); +uint64_t ti_sysc_get_syss_address(device_t dev); +uint64_t ti_sysc_get_syss_address_offset_host(device_t dev); +int ti_sysc_clock_enable(device_t dev); +int ti_sysc_clock_disable(device_t dev); + +uint32_t ti_sysc_get_soft_reset_bit(device_t dev); + +#endif /* __TI_SYSC__ */ Index: head/sys/arm/ti/ti_sysc.c =================================================================== --- head/sys/arm/ti/ti_sysc.c +++ head/sys/arm/ti/ti_sysc.c @@ -1,6 +1,8 @@ /*- * Copyright (c) 2019 Emmanuel Vadot * + * Copyright (c) 2020 Oskar Holmlund + * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: @@ -34,6 +36,7 @@ #include #include #include +#include #include #include #include @@ -47,21 +50,402 @@ #include #include +#include + +#include +#include + +#define DEBUG_SYSC 0 + +#if DEBUG_SYSC +#define DPRINTF(dev, msg...) device_printf(dev, msg) +#else +#define DPRINTF(dev, msg...) +#endif + +/* Documentation/devicetree/bindings/bus/ti-sysc.txt + * + * Documentation/devicetree/clock/clock-bindings.txt + * Defines phandle + optional pair + * Documentation/devicetree/clock/ti-clkctl.txt + */ + +static int ti_sysc_probe(device_t dev); +static int ti_sysc_attach(device_t dev); +static int ti_sysc_detach(device_t dev); + +#define TI_SYSC_DRA7_MCAN 15 +#define TI_SYSC_USB_HOST_FS 14 +#define TI_SYSC_DRA7_MCASP 13 +#define TI_SYSC_MCASP 12 +#define TI_SYSC_OMAP_AES 11 +#define TI_SYSC_OMAP3_SHAM 10 +#define TI_SYSC_OMAP4_SR 9 +#define TI_SYSC_OMAP3630_SR 8 +#define TI_SYSC_OMAP3430_SR 7 +#define TI_SYSC_OMAP4_TIMER 6 +#define TI_SYSC_OMAP2_TIMER 5 +/* Above needs special workarounds */ +#define TI_SYSC_OMAP4_SIMPLE 4 +#define TI_SYSC_OMAP4 3 +#define TI_SYSC_OMAP2 2 +#define TI_SYSC 1 +#define TI_SYSC_END 0 + static struct ofw_compat_data compat_data[] = { - { "ti,sysc", 1 }, - { NULL, 0 } + { "ti,sysc-dra7-mcan", TI_SYSC_DRA7_MCAN }, + { "ti,sysc-usb-host-fs", TI_SYSC_USB_HOST_FS }, + { "ti,sysc-dra7-mcasp", TI_SYSC_DRA7_MCASP }, + { "ti,sysc-mcasp", TI_SYSC_MCASP }, + { "ti,sysc-omap-aes", TI_SYSC_OMAP_AES }, + { "ti,sysc-omap3-sham", TI_SYSC_OMAP3_SHAM }, + { "ti,sysc-omap4-sr", TI_SYSC_OMAP4_SR }, + { "ti,sysc-omap3630-sr", TI_SYSC_OMAP3630_SR }, + { "ti,sysc-omap3430-sr", TI_SYSC_OMAP3430_SR }, + { "ti,sysc-omap4-timer", TI_SYSC_OMAP4_TIMER }, + { "ti,sysc-omap2-timer", TI_SYSC_OMAP2_TIMER }, + /* Above needs special workarounds */ + { "ti,sysc-omap4-simple", TI_SYSC_OMAP4_SIMPLE }, + { "ti,sysc-omap4", TI_SYSC_OMAP4 }, + { "ti,sysc-omap2", TI_SYSC_OMAP2 }, + { "ti,sysc", TI_SYSC }, + { NULL, TI_SYSC_END } }; +/* reg-names can be "rev", "sysc" and "syss" */ +static const char * reg_names[] = { "rev", "sysc", "syss" }; +#define REG_REV 0 +#define REG_SYSC 1 +#define REG_SYSS 2 +#define REG_MAX 3 + +/* master idle / slave idle mode defined in 8.1.3.2.1 / 8.1.3.2.2 */ +#include +#define SYSC_IDLE_MAX 4 + +struct sysc_reg { + uint64_t address; + uint64_t size; +}; + +struct clk_list { + TAILQ_ENTRY(clk_list) next; + clk_t clk; +}; + struct ti_sysc_softc { struct simplebus_softc sc; + bool attach_done; + device_t dev; + int device_type; + + struct sysc_reg reg[REG_MAX]; + /* Offset from host base address */ + uint64_t offset_reg[REG_MAX]; + + uint32_t ti_sysc_mask; + int32_t ti_sysc_midle[SYSC_IDLE_MAX]; + int32_t ti_sysc_sidle[SYSC_IDLE_MAX]; + uint32_t ti_sysc_delay_us; + uint32_t ti_syss_mask; + + int num_clocks; + TAILQ_HEAD(, clk_list) clk_list; + + /* deprecated ti_hwmods */ + bool ti_no_reset_on_init; + bool ti_no_idle_on_init; + bool ti_no_idle; }; -static int ti_sysc_probe(device_t dev); -static int ti_sysc_attach(device_t dev); -static int ti_sysc_detach(device_t dev); +/* + * All sysc seems to have a reg["rev"] register. + * Lets use that for identification of which module the driver are connected to. + */ +uint64_t +ti_sysc_get_rev_address(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + return (sc->reg[REG_REV].address); +} + +uint64_t +ti_sysc_get_rev_address_offset_host(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->offset_reg[REG_REV]); +} + +uint64_t +ti_sysc_get_sysc_address(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->reg[REG_SYSC].address); +} + +uint64_t +ti_sysc_get_sysc_address_offset_host(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->offset_reg[REG_SYSC]); +} + +uint64_t +ti_sysc_get_syss_address(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->reg[REG_SYSS].address); +} + +uint64_t +ti_sysc_get_syss_address_offset_host(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + + return (sc->offset_reg[REG_SYSS]); +} + +/* + * Due no memory region is assigned the sysc driver the children needs to + * handle the practical read/writes to the registers. + * Check if sysc has reset bit. + */ +uint32_t +ti_sysc_get_soft_reset_bit(device_t dev) { + struct ti_sysc_softc *sc = device_get_softc(dev); + switch (sc->device_type) { + case TI_SYSC_OMAP4_TIMER: + case TI_SYSC_OMAP4_SIMPLE: + case TI_SYSC_OMAP4: + if (sc->ti_sysc_mask & SYSC_OMAP4_SOFTRESET) { + return (SYSC_OMAP4_SOFTRESET); + } + break; + + case TI_SYSC_OMAP2_TIMER: + case TI_SYSC_OMAP2: + case TI_SYSC: + if (sc->ti_sysc_mask & SYSC_OMAP2_SOFTRESET) { + return (SYSC_OMAP2_SOFTRESET); + } + break; + default: + break; + } + + return (0); +} + +int +ti_sysc_clock_enable(device_t dev) { + struct clk_list *clkp, *clkp_tmp; + struct ti_sysc_softc *sc = device_get_softc(dev); + int err; + + TAILQ_FOREACH_SAFE(clkp, &sc->clk_list, next, clkp_tmp) { + err = clk_enable(clkp->clk); + + if (err) { + DPRINTF(sc->dev, "clk_enable %s failed %d\n", + clk_get_name(clkp->clk), err); + break; + } + } + return (err); +} + +int +ti_sysc_clock_disable(device_t dev) { + struct clk_list *clkp, *clkp_tmp; + struct ti_sysc_softc *sc = device_get_softc(dev); + int err = 0; + + TAILQ_FOREACH_SAFE(clkp, &sc->clk_list, next, clkp_tmp) { + err = clk_disable(clkp->clk); + + if (err) { + DPRINTF(sc->dev, "clk_enable %s failed %d\n", + clk_get_name(clkp->clk), err); + break; + } + } + return (err); +} + static int +parse_regfields(struct ti_sysc_softc *sc) { + phandle_t node; + uint32_t parent_address_cells; + uint32_t parent_size_cells; + cell_t *reg; + ssize_t nreg; + int err, k, reg_i, prop_idx; + uint32_t idx; + + node = ofw_bus_get_node(sc->dev); + + /* Get parents address and size properties */ + err = OF_searchencprop(OF_parent(node), "#address-cells", + &parent_address_cells, sizeof(parent_address_cells)); + if (err == -1) + return (ENXIO); + if (!(parent_address_cells == 1 || parent_address_cells == 2)) { + DPRINTF(sc->dev, "Expect parent #address-cells=[1||2]\n"); + return (ENXIO); + } + + err = OF_searchencprop(OF_parent(node), "#size-cells", + &parent_size_cells, sizeof(parent_size_cells)); + if (err == -1) + return (ENXIO); + + if (!(parent_size_cells == 1 || parent_size_cells == 2)) { + DPRINTF(sc->dev, "Expect parent #size-cells = [1||2]\n"); + return (ENXIO); + } + + /* Grab the content of reg properties */ + nreg = OF_getproplen(node, "reg"); + reg = malloc(nreg, M_DEVBUF, M_WAITOK); + OF_getencprop(node, "reg", reg, nreg); + + /* Make sure address & size are 0 */ + for (idx = 0; idx < REG_MAX; idx++) { + sc->reg[idx].address = 0; + sc->reg[idx].size = 0; + } + + /* Loop through reg-names and figure out which reg-name corresponds to + * index populate the values into the reg array. + */ + for (idx = 0, reg_i = 0; idx < REG_MAX && reg_i < nreg; idx++) { + err = ofw_bus_find_string_index(node, "reg-names", + reg_names[idx], &prop_idx); + if (err != 0) + continue; + + for (k = 0; k < parent_address_cells; k++) { + sc->reg[prop_idx].address <<= 32; + sc->reg[prop_idx].address |= reg[reg_i++]; + } + + for (k = 0; k < parent_size_cells; k++) { + sc->reg[prop_idx].size <<= 32; + sc->reg[prop_idx].size |= reg[reg_i++]; + } + + if (sc->sc.nranges == 0) + sc->offset_reg[prop_idx] = sc->reg[prop_idx].address; + else + sc->offset_reg[prop_idx] = sc->reg[prop_idx].address - + sc->sc.ranges[REG_REV].host; + + DPRINTF(sc->dev, "reg[%s] adress %#jx size %#jx\n", + reg_names[idx], + sc->reg[prop_idx].address, + sc->reg[prop_idx].size); + } + free(reg, M_DEVBUF); + return (0); +} + +static void +parse_idle(struct ti_sysc_softc *sc, const char *name, uint32_t *idle) { + phandle_t node; + cell_t value[SYSC_IDLE_MAX]; + int len, no, i; + + node = ofw_bus_get_node(sc->dev); + + if (!OF_hasprop(node, name)) { + return; + } + + len = OF_getproplen(node, name); + no = len / sizeof(cell_t); + if (no >= SYSC_IDLE_MAX) { + DPRINTF(sc->dev, "Limit %s\n", name); + no = SYSC_IDLE_MAX-1; + len = no * sizeof(cell_t); + } + + OF_getencprop(node, name, value, len); + for (i = 0; i < no; i++) { + idle[i] = value[i]; +#if DEBUG_SYSC + DPRINTF(sc->dev, "%s[%d] = %d ", + name, i, value[i]); + switch(value[i]) { + case SYSC_IDLE_FORCE: + DPRINTF(sc->dev, "SYSC_IDLE_FORCE\n"); + break; + case SYSC_IDLE_NO: + DPRINTF(sc->dev, "SYSC_IDLE_NO\n"); + break; + case SYSC_IDLE_SMART: + DPRINTF(sc->dev, "SYSC_IDLE_SMART\n"); + break; + case SYSC_IDLE_SMART_WKUP: + DPRINTF(sc->dev, "SYSC_IDLE_SMART_WKUP\n"); + break; + } +#endif + } + for ( ; i < SYSC_IDLE_MAX; i++) + idle[i] = -1; +} + +static int +ti_sysc_attach_clocks(struct ti_sysc_softc *sc) { + clk_t *clk; + struct clk_list *clkp; + int index, err; + phandle_t cnode; + + clk = malloc(sc->num_clocks*sizeof(clk_t), M_DEVBUF, M_WAITOK | M_ZERO); + + cnode = ofw_bus_get_node(sc->dev); + + /* Check if all clocks can be found */ + for (index = 0; index < sc->num_clocks; index++) { + err = clk_get_by_ofw_index(sc->dev, 0, index, &clk[index]); + + if (err != 0) { + free(clk, M_DEVBUF); + return (1); + } + } + + /* All clocks are found, add to list */ + for (index = 0; index < sc->num_clocks; index++) { + clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO); + clkp->clk = clk[index]; + TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next); + } + + /* Release the clk array */ + free(clk, M_DEVBUF); + return (0); +} + +static int +ti_sysc_simplebus_attach_child(device_t dev) { + device_t cdev; + phandle_t node, child; + struct ti_sysc_softc *sc = device_get_softc(dev); + + node = ofw_bus_get_node(sc->dev); + + for (child = OF_child(node); child > 0; child = OF_peer(child)) { + cdev = simplebus_add_device(sc->dev, child, 0, NULL, -1, NULL); + if (cdev != NULL) + device_probe_and_attach(cdev); + } + return (0); +} + +/* Device interface */ +static int ti_sysc_probe(device_t dev) { if (!ofw_bus_status_okay(dev)) @@ -71,8 +455,6 @@ return (ENXIO); device_set_desc(dev, "TI SYSC Interconnect"); - if (!bootverbose) - device_quiet(dev); return (BUS_PROBE_DEFAULT); } @@ -81,48 +463,160 @@ ti_sysc_attach(device_t dev) { struct ti_sysc_softc *sc; - device_t cdev; - phandle_t node, child; + phandle_t node; + int err; + cell_t value; sc = device_get_softc(dev); sc->dev = dev; - node = ofw_bus_get_node(dev); + sc->device_type = ofw_bus_search_compatible(dev, compat_data)->ocd_data; - simplebus_init(dev, node); + node = ofw_bus_get_node(sc->dev); + /* ranges - use simplebus */ + simplebus_init(sc->dev, node); if (simplebus_fill_ranges(node, &sc->sc) < 0) { - device_printf(dev, "could not get ranges\n"); + DPRINTF(sc->dev, "could not get ranges\n"); return (ENXIO); } - for (child = OF_child(node); child > 0; child = OF_peer(child)) { - cdev = simplebus_add_device(dev, child, 0, NULL, -1, NULL); - if (cdev != NULL) - device_probe_and_attach(cdev); + if (sc->sc.nranges == 0) { + DPRINTF(sc->dev, "nranges == 0\n"); + return (ENXIO); } - return (bus_generic_attach(dev)); + /* Required field reg & reg-names - assume at least "rev" exists */ + err = parse_regfields(sc); + if (err) { + DPRINTF(sc->dev, "parse_regfields failed %d\n", err); + return (ENXIO); + } + + /* Optional */ + if (OF_hasprop(node, "ti,sysc-mask")) { + OF_getencprop(node, "ti,sysc-mask", &value, sizeof(cell_t)); + sc->ti_sysc_mask = value; + } + if (OF_hasprop(node, "ti,syss-mask")) { + OF_getencprop(node, "ti,syss-mask", &value, sizeof(cell_t)); + sc->ti_syss_mask = value; + } + if (OF_hasprop(node, "ti,sysc-delay-us")) { + OF_getencprop(node, "ti,sysc-delay-us", &value, sizeof(cell_t)); + sc->ti_sysc_delay_us = value; + } + + DPRINTF(sc->dev, "sysc_mask %x syss_mask %x delay_us %x\n", + sc->ti_sysc_mask, sc->ti_syss_mask, sc->ti_sysc_delay_us); + + parse_idle(sc, "ti,sysc-midle", sc->ti_sysc_midle); + parse_idle(sc, "ti,sysc-sidle", sc->ti_sysc_sidle); + + if (OF_hasprop(node, "ti,no-reset-on-init")) + sc->ti_no_reset_on_init = true; + else + sc->ti_no_reset_on_init = false; + + if (OF_hasprop(node, "ti,no-idle-on-init")) + sc->ti_no_idle_on_init = true; + else + sc->ti_no_idle_on_init = false; + + if (OF_hasprop(node, "ti,no-idle")) + sc->ti_no_idle = true; + else + sc->ti_no_idle = false; + + DPRINTF(sc->dev, + "no-reset-on-init %d, no-idle-on-init %d, no-idle %d\n", + sc->ti_no_reset_on_init, + sc->ti_no_idle_on_init, + sc->ti_no_idle); + + if (OF_hasprop(node, "clocks")) { + struct clock_cell_info cell_info; + read_clock_cells(sc->dev, &cell_info); + free(cell_info.clock_cells, M_DEVBUF); + free(cell_info.clock_cells_ncells, M_DEVBUF); + + sc->num_clocks = cell_info.num_real_clocks; + TAILQ_INIT(&sc->clk_list); + + err = ti_sysc_attach_clocks(sc); + if (err) { + DPRINTF(sc->dev, "Failed to attach clocks\n"); + return (bus_generic_attach(sc->dev)); + } + } + + err = ti_sysc_simplebus_attach_child(sc->dev); + if (err) { + DPRINTF(sc->dev, "ti_sysc_simplebus_attach_child %d\n", + err); + return (err); + } + + sc->attach_done = true; + + return (bus_generic_attach(sc->dev)); } static int ti_sysc_detach(device_t dev) { - return (EBUSY); } +/* Bus interface */ +static void +ti_sysc_new_pass(device_t dev) +{ + struct ti_sysc_softc *sc; + int err; + phandle_t node; + + sc = device_get_softc(dev); + + if (sc->attach_done) { + bus_generic_new_pass(sc->dev); + return; + } + + node = ofw_bus_get_node(sc->dev); + if (OF_hasprop(node, "clocks")) { + err = ti_sysc_attach_clocks(sc); + if (err) { + DPRINTF(sc->dev, "Failed to attach clocks\n"); + return; + } + } + + err = ti_sysc_simplebus_attach_child(sc->dev); + if (err) { + DPRINTF(sc->dev, + "ti_sysc_simplebus_attach_child failed %d\n", err); + return; + } + sc->attach_done = true; + + bus_generic_attach(sc->dev); +} + static device_method_t ti_sysc_methods[] = { /* Device interface */ DEVMETHOD(device_probe, ti_sysc_probe), DEVMETHOD(device_attach, ti_sysc_attach), DEVMETHOD(device_detach, ti_sysc_detach), + /* Bus interface */ + DEVMETHOD(bus_new_pass, ti_sysc_new_pass), + DEVMETHOD_END }; DEFINE_CLASS_1(ti_sysc, ti_sysc_driver, ti_sysc_methods, - sizeof(struct ti_sysc_softc), simplebus_driver); + sizeof(struct ti_sysc_softc), simplebus_driver); static devclass_t ti_sysc_devclass; EARLY_DRIVER_MODULE(ti_sysc, simplebus, ti_sysc_driver, -ti_sysc_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); + ti_sysc_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_FIRST); Index: head/sys/arm/ti/ti_wdt.c =================================================================== --- head/sys/arm/ti/ti_wdt.c +++ head/sys/arm/ti/ti_wdt.c @@ -49,7 +49,6 @@ #include -#include #include #ifdef DEBUG @@ -93,6 +92,7 @@ static devclass_t ti_wdt_devclass; DRIVER_MODULE(ti_wdt, simplebus, ti_wdt_driver, ti_wdt_devclass, 0, 0); +MODULE_DEPEND(ti_wdt, ti_sysc, 1, 1, 1); static __inline uint32_t ti_wdt_reg_read(struct ti_wdt_softc *sc, uint32_t reg) Index: head/sys/arm/ti/usb/omap_ehci.c =================================================================== --- head/sys/arm/ti/usb/omap_ehci.c +++ head/sys/arm/ti/usb/omap_ehci.c @@ -57,7 +57,6 @@ #include -#include #include #include Index: head/sys/arm/ti/usb/omap_host.c =================================================================== --- head/sys/arm/ti/usb/omap_host.c +++ head/sys/arm/ti/usb/omap_host.c @@ -40,7 +40,7 @@ #include -#include +#include #include /* @@ -139,12 +139,14 @@ int i; /* Enable Clocks for high speed USBHOST */ - ti_prcm_clk_enable(USBHSHOST_CLK); + ti_sysc_clock_enable(device_get_parent(isc->sc_dev)); /* Read the UHH revision */ isc->uhh_rev = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_REVISION); device_printf(isc->sc_dev, "UHH revision 0x%08x\n", isc->uhh_rev); + /* FIXME */ +#if 0 if (isc->uhh_rev == OMAP_UHH_REV2) { /* For OMAP44xx devices you have to enable the per-port clocks: * PHY_MODE - External ULPI clock @@ -200,6 +202,7 @@ device_printf(isc->sc_dev, "unknown port mode %d for port 1\n", isc->port_mode[1]); } } +#endif /* Put UHH in SmartIdle/SmartStandby mode */ reg = omap_uhh_read_4(isc, OMAP_USBHOST_UHH_SYSCONFIG); @@ -327,7 +330,7 @@ } /* Disable functional and interface clocks for the TLL and HOST modules */ - ti_prcm_clk_disable(USBHSHOST_CLK); + ti_sysc_clock_disable(device_get_parent(isc->sc_dev)); device_printf(isc->sc_dev, "Clock to USB host has been disabled\n"); } Index: head/sys/arm/ti/usb/omap_tll.c =================================================================== --- head/sys/arm/ti/usb/omap_tll.c +++ head/sys/arm/ti/usb/omap_tll.c @@ -39,7 +39,7 @@ #include -#include +#include #include /* @@ -212,7 +212,7 @@ int ret = 0; /* Enable the USB TLL */ - ti_prcm_clk_enable(USBTLL_CLK); + ti_sysc_clock_enable(device_get_parent(sc->sc_dev)); /* Perform TLL soft reset, and wait until reset is complete */ omap_tll_write_4(sc, OMAP_USBTLL_SYSCONFIG, TLL_SYSCONFIG_SOFTRESET); @@ -248,7 +248,7 @@ err_sys_status: /* Disable the TLL clocks */ - ti_prcm_clk_disable(USBTLL_CLK); + ti_sysc_clock_disable(device_get_parent(sc->sc_dev)); return(ret); } @@ -273,7 +273,7 @@ } /* Disable functional and interface clocks for the TLL and HOST modules */ - ti_prcm_clk_disable(USBTLL_CLK); + ti_sysc_clock_disable(device_get_parent(sc->sc_dev)); } static int Index: head/sys/dev/uart/uart_dev_ti8250.c =================================================================== --- head/sys/dev/uart/uart_dev_ti8250.c +++ head/sys/dev/uart/uart_dev_ti8250.c @@ -39,9 +39,6 @@ #include #include -#include -#include - #include #include #include @@ -52,6 +49,8 @@ #include #include +#include + #include "uart_if.h" /* @@ -74,16 +73,8 @@ ti8250_bus_probe(struct uart_softc *sc) { int status; - clk_ident_t clkid; - /* Enable clocks for this device. We can't continue if that fails. */ - clkid = ti_hwmods_get_clock(sc->sc_dev); - if (clkid == INVALID_CLK_IDENT) { - device_printf(sc->sc_dev, - "failed to get clock based on hwmods\n"); - clkid = UART1_CLK + device_get_unit(sc->sc_dev); - } - if ((status = ti_prcm_clk_enable(clkid)) != 0) + if ((status = ti_sysc_clock_enable(device_get_parent(sc->sc_dev))) != 0) return (status); /* Index: head/sys/modules/Makefile =================================================================== --- head/sys/modules/Makefile +++ head/sys/modules/Makefile @@ -755,7 +755,7 @@ _sbni= sbni .endif -.if ${MACHINE_CPUARCH} == "arm" +.if ${MACHINE_ARCH} == "armv7" _cfi= cfi _cpsw= cpsw .endif