From 0050ea241584f931c6089f7b7a7aca3804131397 Mon Sep 17 00:00:00 2001 From: Michal Meloun Date: Thu, 30 Jul 2020 14:45:05 +0000 Subject: [PATCH] Move Ti AM335x to dev/extres/clk framework. Re-implement clocks for these SoC by using now standard extres/clk framework. This is necessary for future expansion of these. The new implementation is (due to the size of the patch) only the initial (minimum) version. It will be updated/expanded with a subsequent set of particular patches. This patch is also not tested on OMAP4 based boards (BeagleBone), so all possible issues should be (and will be) fixed by ASAP once identified. Submited by: Oskar Holmlund (oskar.holmlund@ohdata.se) Differential Revision: https://reviews.freebsd.org/D25118 --- sys/arm/ti/am335x/am3359_cppi41.c | 192 +++++++ sys/arm/ti/am335x/am335x_dmtimer.c | 84 ++- sys/arm/ti/am335x/am335x_dmtpps.c | 114 +++- sys/arm/ti/am335x/am335x_dmtreg.h | 12 + sys/arm/ti/am335x/am335x_gpio.c | 1 + sys/arm/ti/am335x/am335x_lcd.c | 33 +- sys/arm/ti/am335x/am335x_musb.c | 71 ++- sys/arm/ti/am335x/am335x_prcm.c | 884 ----------------------------- sys/arm/ti/am335x/am335x_pwmss.c | 66 ++- sys/arm/ti/am335x/am335x_rtc.c | 6 +- sys/arm/ti/am335x/am335x_scm.c | 44 +- sys/arm/ti/am335x/am335x_usb_phy.c | 121 ++++ sys/arm/ti/am335x/am335x_usbss.c | 226 -------- sys/arm/ti/am335x/files.am335x | 4 +- sys/arm/ti/clk/clock_common.c | 152 +++++ sys/arm/ti/clk/clock_common.h | 43 ++ sys/arm/ti/clk/ti_clk_clkctrl.c | 219 +++++++ sys/arm/ti/clk/ti_clk_clkctrl.h | 43 ++ sys/arm/ti/clk/ti_clk_dpll.c | 341 +++++++++++ sys/arm/ti/clk/ti_clk_dpll.h | 97 ++++ sys/arm/ti/clk/ti_clkctrl.c | 353 ++++++++++++ sys/arm/ti/clk/ti_divider_clock.c | 264 +++++++++ sys/arm/ti/clk/ti_dpll_clock.c | 375 ++++++++++++ sys/arm/ti/clk/ti_gate_clock.c | 266 +++++++++ sys/arm/ti/clk/ti_mux_clock.c | 249 ++++++++ sys/arm/ti/cpsw/if_cpsw.c | 28 +- sys/arm/ti/files.ti | 13 +- sys/arm/ti/omap4/files.omap4 | 2 +- sys/arm/ti/ti_adc.c | 7 +- sys/arm/ti/ti_edma3.c | 13 +- sys/arm/ti/ti_gpio.c | 82 ++- sys/arm/ti/ti_hwmods.c | 214 ------- sys/arm/ti/ti_hwmods.h | 37 -- sys/arm/ti/ti_i2c.c | 20 +- sys/arm/ti/ti_mbox.c | 9 +- sys/arm/ti/ti_omap4_cm.c | 151 +++++ sys/arm/ti/ti_omap4_cm.h | 34 ++ sys/arm/ti/ti_pinmux.c | 2 + sys/arm/ti/ti_prcm.c | 642 ++++++++++----------- sys/arm/ti/ti_prcm.h | 208 +------ sys/arm/ti/ti_prm.c | 210 +++++++ sys/arm/ti/ti_prm.h | 38 ++ sys/arm/ti/ti_pruss.c | 96 +++- sys/arm/ti/ti_scm.c | 203 +++---- sys/arm/ti/ti_scm_syscon.c | 294 ++++++++++ sys/arm/ti/ti_sdhci.c | 63 +- sys/arm/ti/ti_sdma.c | 19 +- sys/arm/ti/ti_spi.c | 24 +- sys/arm/ti/ti_sysc.c | 540 +++++++++++++++++- sys/arm/ti/ti_sysc.h | 43 ++ sys/arm/ti/ti_wdt.c | 2 +- sys/arm/ti/usb/omap_ehci.c | 1 - sys/arm/ti/usb/omap_host.c | 9 +- sys/arm/ti/usb/omap_tll.c | 8 +- sys/dev/uart/uart_dev_ti8250.c | 15 +- sys/modules/Makefile | 2 +- 56 files changed, 5050 insertions(+), 2239 deletions(-) create mode 100644 sys/arm/ti/am335x/am3359_cppi41.c delete mode 100644 sys/arm/ti/am335x/am335x_prcm.c create mode 100644 sys/arm/ti/am335x/am335x_usb_phy.c delete mode 100644 sys/arm/ti/am335x/am335x_usbss.c create mode 100644 sys/arm/ti/clk/clock_common.c create mode 100644 sys/arm/ti/clk/clock_common.h create mode 100644 sys/arm/ti/clk/ti_clk_clkctrl.c create mode 100644 sys/arm/ti/clk/ti_clk_clkctrl.h create mode 100644 sys/arm/ti/clk/ti_clk_dpll.c create mode 100644 sys/arm/ti/clk/ti_clk_dpll.h create mode 100644 sys/arm/ti/clk/ti_clkctrl.c create mode 100644 sys/arm/ti/clk/ti_divider_clock.c create mode 100644 sys/arm/ti/clk/ti_dpll_clock.c create mode 100644 sys/arm/ti/clk/ti_gate_clock.c create mode 100644 sys/arm/ti/clk/ti_mux_clock.c delete mode 100644 sys/arm/ti/ti_hwmods.c delete mode 100644 sys/arm/ti/ti_hwmods.h create mode 100644 sys/arm/ti/ti_omap4_cm.c create mode 100644 sys/arm/ti/ti_omap4_cm.h create mode 100644 sys/arm/ti/ti_prm.c create mode 100644 sys/arm/ti/ti_prm.h create mode 100644 sys/arm/ti/ti_scm_syscon.c create mode 100644 sys/arm/ti/ti_sysc.h diff --git a/sys/arm/ti/am335x/am3359_cppi41.c b/sys/arm/ti/am335x/am3359_cppi41.c new file mode 100644 index 000000000000..a3e4e8bee155 --- /dev/null +++ b/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); diff --git a/sys/arm/ti/am335x/am335x_dmtimer.c b/sys/arm/ti/am335x/am335x_dmtimer.c index a36c66e56ed0..eb869ca88b94 100644 --- a/sys/arm/ti/am335x/am335x_dmtimer.c +++ b/sys/arm/ti/am335x/am335x_dmtimer.c @@ -42,12 +42,13 @@ __FBSDID("$FreeBSD$"); #include /* For arm_set_delay */ +#include + #include #include #include -#include -#include +#include #include "am335x_dmtreg.h" @@ -58,7 +59,8 @@ struct am335x_dmtimer_softc { 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 @@ am335x_dmtimer_probe(device_t dev) { char strbuf[32]; int tmr_num; + uint64_t rev_address; if (!ofw_bus_status_okay(dev)) return (ENXIO); @@ -259,13 +262,22 @@ am335x_dmtimer_probe(device_t dev) 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,23 +289,46 @@ static int 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, @@ -302,7 +337,20 @@ am335x_dmtimer_attach(device_t dev) 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 driver_t am335x_dmtimer_driver = { 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) diff --git a/sys/arm/ti/am335x/am335x_dmtpps.c b/sys/arm/ti/am335x/am335x_dmtpps.c index 6aa374a0f76f..24d83f248eef 100644 --- a/sys/arm/ti/am335x/am335x_dmtpps.c +++ b/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 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include -#include -#include +#include #include #include @@ -82,6 +84,8 @@ struct dmtpps_softc { 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 @@ dmtpps_probe(device_t dev) { char strbuf[64]; int tmr_num; + uint64_t rev_address; if (!ofw_bus_status_okay(dev)) return (ENXIO); @@ -402,7 +407,33 @@ dmtpps_probe(device_t dev) * 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 @@ dmtpps_attach(device_t dev) { 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 @@ dmtpps_attach(device_t dev) 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 @@ dmtpps_attach(device_t dev) 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 driver_t dmtpps_driver = { 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); diff --git a/sys/arm/ti/am335x/am335x_dmtreg.h b/sys/arm/ti/am335x/am335x_dmtreg.h index f2ef54ddb917..c91a30570bd8 100644 --- a/sys/arm/ti/am335x/am335x_dmtreg.h +++ b/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 */ diff --git a/sys/arm/ti/am335x/am335x_gpio.c b/sys/arm/ti/am335x/am335x_gpio.c index cbfde175c2e7..beb169b3e4b5 100644 --- a/sys/arm/ti/am335x/am335x_gpio.c +++ b/sys/arm/ti/am335x/am335x_gpio.c @@ -155,3 +155,4 @@ DEFINE_CLASS_1(gpio, am335x_gpio_driver, am335x_gpio_methods, 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); diff --git a/sys/arm/ti/am335x/am335x_lcd.c b/sys/arm/ti/am335x/am335x_lcd.c index 5c60bf4be6bf..387bd37e3ebf 100644 --- a/sys/arm/ti/am335x/am335x_lcd.c +++ b/sys/arm/ti/am335x/am335x_lcd.c @@ -50,6 +50,8 @@ __FBSDID("$FreeBSD$"); #include +#include + #include #include #include @@ -65,7 +67,7 @@ __FBSDID("$FreeBSD$"); #include #endif -#include +#include #include #include "am335x_lcd.h" @@ -219,6 +221,9 @@ struct am335x_lcd_softc { /* 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 @@ am335x_lcd_configure(struct am335x_lcd_softc *sc) 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 @@ am335x_lcd_attach(device_t dev) 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 @@ am335x_lcd_attach(device_t dev) } } - 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 @@ static devclass_t am335x_lcd_devclass; 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); diff --git a/sys/arm/ti/am335x/am335x_musb.c b/sys/arm/ti/am335x/am335x_musb.c index cbe4d06338c9..d868e8a64f8b 100644 --- a/sys/arm/ti/am335x/am335x_musb.c +++ b/sys/arm/ti/am335x/am335x_musb.c @@ -66,9 +66,11 @@ __FBSDID("$FreeBSD$"); #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_super_softc { struct musbotg_softc sc_otg; struct resource *sc_mem_res[2]; int sc_irq_rid; + struct syscon *syscon; }; static void @@ -155,30 +158,33 @@ static void 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 @@ musbotg_attach(device_t dev) 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 driver_t musbotg_driver = { 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); diff --git a/sys/arm/ti/am335x/am335x_prcm.c b/sys/arm/ti/am335x/am335x_prcm.c deleted file mode 100644 index 875be72f4937..000000000000 --- a/sys/arm/ti/am335x/am335x_prcm.c +++ /dev/null @@ -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); -} diff --git a/sys/arm/ti/am335x/am335x_pwmss.c b/sys/arm/ti/am335x/am335x_pwmss.c index 814865d6b762..287b6ce9e8fe 100644 --- a/sys/arm/ti/am335x/am335x_pwmss.c +++ b/sys/arm/ti/am335x/am335x_pwmss.c @@ -46,9 +46,10 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include +#include + +#include +#include "syscon_if.h" #include "am335x_pwm.h" #include "am335x_scm.h" @@ -59,6 +60,11 @@ __FBSDID("$FreeBSD$"); #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 @@ static device_detach_t am335x_pwmss_detach; 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 @@ am335x_pwmss_attach(device_t dev) { 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 @@ DEFINE_CLASS_1(am335x_pwmss, am335x_pwmss_driver, am335x_pwmss_methods, 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); diff --git a/sys/arm/ti/am335x/am335x_rtc.c b/sys/arm/ti/am335x/am335x_rtc.c index 9620f5284e84..c2612d2fc7a9 100644 --- a/sys/arm/ti/am335x/am335x_rtc.c +++ b/sys/arm/ti/am335x/am335x_rtc.c @@ -39,8 +39,9 @@ __FBSDID("$FreeBSD$"); #include +#include #include -#include +#include #include #include @@ -110,7 +111,7 @@ am335x_rtc_attach(device_t dev) 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 @@ static devclass_t am335x_rtc_devclass; 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); diff --git a/sys/arm/ti/am335x/am335x_scm.c b/sys/arm/ti/am335x/am335x_scm.c index 6f040ed74b7d..e72c14ba58ad 100644 --- a/sys/arm/ti/am335x/am335x_scm.c +++ b/sys/arm/ti/am335x/am335x_scm.c @@ -40,11 +40,15 @@ __FBSDID("$FreeBSD$"); #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 @@ am335x_scm_temp_sysctl(SYSCTL_HANDLER_ARGS) /* 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 @@ am335x_scm_identify(driver_t *driver, device_t parent) 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 @@ am335x_scm_attach(device_t dev) 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 @@ am335x_scm_detach(device_t dev) 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 @@ static devclass_t am335x_scm_devclass; 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); diff --git a/sys/arm/ti/am335x/am335x_usb_phy.c b/sys/arm/ti/am335x/am335x_usb_phy.c new file mode 100644 index 000000000000..00e28122dcec --- /dev/null +++ b/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); diff --git a/sys/arm/ti/am335x/am335x_usbss.c b/sys/arm/ti/am335x/am335x_usbss.c deleted file mode 100644 index ce78a7b64315..000000000000 --- a/sys/arm/ti/am335x/am335x_usbss.c +++ /dev/null @@ -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); diff --git a/sys/arm/ti/am335x/files.am335x b/sys/arm/ti/am335x/files.am335x index 66af0d867847..4ecdc1e35b43 100644 --- a/sys/arm/ti/am335x/files.am335x +++ b/sys/arm/ti/am335x/files.am335x @@ -8,7 +8,6 @@ arm/ti/am335x/am335x_gpio.c optional gpio 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_ecap.c standard 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 diff --git a/sys/arm/ti/clk/clock_common.c b/sys/arm/ti/clk/clock_common.c new file mode 100644 index 000000000000..15b0e75a8a1e --- /dev/null +++ b/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); +} diff --git a/sys/arm/ti/clk/clock_common.h b/sys/arm/ti/clk/clock_common.h new file mode 100644 index 000000000000..148494f90331 --- /dev/null +++ b/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); diff --git a/sys/arm/ti/clk/ti_clk_clkctrl.c b/sys/arm/ti/clk/ti_clk_clkctrl.c new file mode 100644 index 000000000000..6b2fff5e12bb --- /dev/null +++ b/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); +} diff --git a/sys/arm/ti/clk/ti_clk_clkctrl.h b/sys/arm/ti/clk/ti_clk_clkctrl.h new file mode 100644 index 000000000000..d78736244815 --- /dev/null +++ b/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_ */ diff --git a/sys/arm/ti/clk/ti_clk_dpll.c b/sys/arm/ti/clk/ti_clk_dpll.c new file mode 100644 index 000000000000..14e48dc95026 --- /dev/null +++ b/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); +} diff --git a/sys/arm/ti/clk/ti_clk_dpll.h b/sys/arm/ti/clk/ti_clk_dpll.h new file mode 100644 index 000000000000..54bc0b988d6e --- /dev/null +++ b/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_ */ diff --git a/sys/arm/ti/clk/ti_clkctrl.c b/sys/arm/ti/clk/ti_clkctrl.c new file mode 100644 index 000000000000..5ba0dbe19b79 --- /dev/null +++ b/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); diff --git a/sys/arm/ti/clk/ti_divider_clock.c b/sys/arm/ti/clk/ti_divider_clock.c new file mode 100644 index 000000000000..753b5f535d29 --- /dev/null +++ b/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); diff --git a/sys/arm/ti/clk/ti_dpll_clock.c b/sys/arm/ti/clk/ti_dpll_clock.c new file mode 100644 index 000000000000..91127c570c4d --- /dev/null +++ b/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); diff --git a/sys/arm/ti/clk/ti_gate_clock.c b/sys/arm/ti/clk/ti_gate_clock.c new file mode 100644 index 000000000000..b4fb65995e74 --- /dev/null +++ b/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); diff --git a/sys/arm/ti/clk/ti_mux_clock.c b/sys/arm/ti/clk/ti_mux_clock.c new file mode 100644 index 000000000000..bd232290e6a0 --- /dev/null +++ b/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); diff --git a/sys/arm/ti/cpsw/if_cpsw.c b/sys/arm/ti/cpsw/if_cpsw.c index 4503304e7b5b..9c43419d568b 100644 --- a/sys/arm/ti/cpsw/if_cpsw.c +++ b/sys/arm/ti/cpsw/if_cpsw.c @@ -74,7 +74,8 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include +#include "syscon_if.h" #include #include @@ -1004,6 +1005,8 @@ cpswp_attach(device_t dev) 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 @@ cpswp_attach(device_t dev) 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; diff --git a/sys/arm/ti/files.ti b/sys/arm/ti/files.ti index 83b3c2ed8d89..87beccd120a0 100644 --- a/sys/arm/ti/files.ti +++ b/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 @@ -18,6 +20,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 diff --git a/sys/arm/ti/omap4/files.omap4 b/sys/arm/ti/omap4/files.omap4 index ddae056d3fc4..0b2f2d3bf26d 100644 --- a/sys/arm/ti/omap4/files.omap4 +++ b/sys/arm/ti/omap4/files.omap4 @@ -9,7 +9,7 @@ arm/ti/ti_sdma.c optional ti_sdma 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 diff --git a/sys/arm/ti/ti_adc.c b/sys/arm/ti/ti_adc.c index 7d7f1deae580..3c67500f3ebc 100644 --- a/sys/arm/ti/ti_adc.c +++ b/sys/arm/ti/ti_adc.c @@ -58,7 +58,7 @@ __FBSDID("$FreeBSD$"); #include #endif -#include +#include #include #include @@ -824,7 +824,7 @@ ti_adc_attach(device_t dev) } /* 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 @@ ti_adc_attach(device_t dev) } /* 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 @@ static devclass_t ti_adc_devclass; 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 diff --git a/sys/arm/ti/ti_edma3.c b/sys/arm/ti/ti_edma3.c index f8736e001553..7804ee6b1d8d 100644 --- a/sys/arm/ti/ti_edma3.c +++ b/sys/arm/ti/ti_edma3.c @@ -54,7 +54,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include @@ -181,8 +181,10 @@ ti_edma3_attach(device_t dev) 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 driver_t ti_edma3_driver = { 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) @@ -244,11 +246,6 @@ ti_edma3_init(unsigned int eqn) 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); ti_edma3_cc_wr_4(TI_EDMA3CC_EMCRH, 0xFFFFFFFF); diff --git a/sys/arm/ti/ti_gpio.c b/sys/arm/ti/ti_gpio.c index ccdeeb502be4..8754a4769beb 100644 --- a/sys/arm/ti/ti_gpio.c +++ b/sys/arm/ti/ti_gpio.c @@ -57,8 +57,7 @@ __FBSDID("$FreeBSD$"); #include #include #include -#include -#include +#include #include #include @@ -117,6 +116,18 @@ __FBSDID("$FreeBSD$"); #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 @@ ti_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) oe &= ~TI_GPIO_MASK(pin); ti_gpio_write_4(sc, TI_GPIO_OE, oe); TI_GPIO_UNLOCK(sc); - + return (0); } @@ -499,7 +510,7 @@ ti_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *value) 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 @@ ti_gpio_pin_toggle(device_t dev, uint32_t pin) 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 @@ ti_gpio_attach(device_t dev) /* 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. */ diff --git a/sys/arm/ti/ti_hwmods.c b/sys/arm/ti/ti_hwmods.c deleted file mode 100644 index 97c8f99c828a..000000000000 --- a/sys/arm/ti/ti_hwmods.c +++ /dev/null @@ -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); -} diff --git a/sys/arm/ti/ti_hwmods.h b/sys/arm/ti/ti_hwmods.h deleted file mode 100644 index c236cc0d0db0..000000000000 --- a/sys/arm/ti/ti_hwmods.h +++ /dev/null @@ -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_ */ diff --git a/sys/arm/ti/ti_i2c.c b/sys/arm/ti/ti_i2c.c index 4a9313d6f501..526cb45481f0 100644 --- a/sys/arm/ti/ti_i2c.c +++ b/sys/arm/ti/ti_i2c.c @@ -63,8 +63,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include +#include #include #include @@ -79,7 +78,6 @@ __FBSDID("$FreeBSD$"); 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 @@ ti_i2c_activate(device_t dev) * 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 @@ ti_i2c_deactivate(device_t dev) } /* 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 @@ static int 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 @@ ti_i2c_attach(device_t dev) 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 @@ static devclass_t ti_i2c_devclass; 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); diff --git a/sys/arm/ti/ti_mbox.c b/sys/arm/ti/ti_mbox.c index ea8454f96f7a..f77f2d9eafbf 100644 --- a/sys/arm/ti/ti_mbox.c +++ b/sys/arm/ti/ti_mbox.c @@ -50,7 +50,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include "mbox_if.h" @@ -102,6 +102,7 @@ static driver_t ti_mbox_driver = { 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 @@ ti_mbox_attach(device_t dev) 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_attach(device_t dev) */ 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); /* diff --git a/sys/arm/ti/ti_omap4_cm.c b/sys/arm/ti/ti_omap4_cm.c new file mode 100644 index 000000000000..c9545a612e1f --- /dev/null +++ b/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); + diff --git a/sys/arm/ti/ti_omap4_cm.h b/sys/arm/ti/ti_omap4_cm.h new file mode 100644 index 000000000000..4da56520cc97 --- /dev/null +++ b/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__ */ diff --git a/sys/arm/ti/ti_pinmux.c b/sys/arm/ti/ti_pinmux.c index b532d9124ce6..da4b8a85526c 100644 --- a/sys/arm/ti/ti_pinmux.c +++ b/sys/arm/ti/ti_pinmux.c @@ -459,3 +459,5 @@ static driver_t ti_pinmux_driver = { 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); diff --git a/sys/arm/ti/ti_prcm.c b/sys/arm/ti/ti_prcm.c index 3b6bbabe6910..ff85e724ada4 100644 --- a/sys/arm/ti/ti_prcm.c +++ b/sys/arm/ti/ti_prcm.c @@ -1,8 +1,310 @@ /*- - * 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: + * 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/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 "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) +{ + 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? + */ + ti_prcm_sc = sc; + + switch(ti_chip()) { +#ifdef SOC_OMAP4 + case CHIP_OMAP_4: + ti_cpu_reset = omap4_prcm_reset; + break; +#endif +#ifdef SOC_TI_AM335X + case CHIP_AM335X: + ti_cpu_reset = am335x_prcm_reset; + break; +#endif + } + + 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); + } + + return (bus_generic_attach(sc->dev)); +} + +int +ti_prcm_write_4(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct ti_prcm_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); +} +int +ti_prcm_read_4(device_t dev, bus_addr_t addr, uint32_t *val) +{ + struct ti_prcm_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); +} + +int +ti_prcm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) +{ + struct ti_prcm_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); +} + +void +ti_prcm_device_lock(device_t dev) +{ + struct ti_prcm_softc *sc; + + sc = device_get_softc(dev); + mtx_lock(&sc->mtx); +} + +void +ti_prcm_device_unlock(device_t dev) +{ + struct ti_prcm_softc *sc; + + 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), + + /* 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), + + DEVMETHOD_END +}; + +DEFINE_CLASS_1(ti_prcm, ti_prcm_driver, ti_prcm_methods, + sizeof(struct ti_prcm_softc), simplebus_driver); + +static devclass_t ti_prcm_devclass; + +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)); +} + +/* 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 + * + * Copyright (c) 2011 + * Ben Gray . * All rights reserved. * * Redistribution and use in source and binary forms, with or without @@ -13,10 +315,7 @@ * 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 + * 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. * @@ -31,327 +330,16 @@ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ +#define PRM_RSTCTRL 0x1b00 +#define PRM_RSTCTRL_RESET 0x2 -/** - * Power, Reset and Clock Management Module - * - * 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. - * - */ -#include -__FBSDID("$FreeBSD$"); - -#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[]; - -/** - * 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) +static void +omap4_prcm_reset(void) { - 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. - */ - clk_dev = NULL; - switch(ti_chip()) { -#ifdef SOC_OMAP4 - case CHIP_OMAP_4: - clk_dev = &(ti_omap4_clk_devmap[0]); - break; -#endif -#ifdef SOC_TI_AM335X - case CHIP_AM335X: - clk_dev = &(ti_am335x_clk_devmap[0]); - 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++; - } + uint32_t reg; - /* Sanity check we managed to find the clock */ - printf("ti_prcm: Failed to find clock device (%d)\n", clk); - return (NULL); -} - -/** - * 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) -{ - int ret = 0; - - if (ti_prcm_clk_dev(clk) == NULL) - ret = EINVAL; - - return (ret); -} - - -/** - * 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) -{ - struct ti_clock_dev *clk_dev; - int ret; - - /* 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); - - /* 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); -} - - -/** - * 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) -{ - struct ti_clock_dev *clk_dev; - int ret; - - /* 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); - - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); - - /* Activate the clock */ - if (clk_dev->clk_deactivate) - ret = clk_dev->clk_deactivate(clk_dev); - else - ret = EINVAL; - - return (ret); -} - -/** - * 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) -{ - struct ti_clock_dev *clk_dev; - int ret; - - /* 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); - - /* Sanity check we managed to find the clock */ - if (clk_dev == NULL) - return (EINVAL); - - /* Activate the clock */ - if (clk_dev->clk_set_source) - ret = clk_dev->clk_set_source(clk_dev, clksrc); - else - ret = EINVAL; - - return (ret); -} - - -/** - * 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; - - /* 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); - - /* 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_get_source_freq) - ret = clk_dev->clk_get_source_freq(clk_dev, freq); - else - ret = EINVAL; - - return (ret); -} - -/** - * 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 - * - * LOCKING: - * Internally locks the driver context. - * - * RETURNS: - * Returns 0 on success or positive error code on failure. - */ -int -ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq) -{ - struct ti_clock_dev *clk_dev; - int ret; - - 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, ®); } diff --git a/sys/arm/ti/ti_prcm.h b/sys/arm/ti/ti_prcm.h index 6df39436cb2f..98f8abc15dd7 100644 --- a/sys/arm/ti/ti_prcm.h +++ b/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 diff --git a/sys/arm/ti/ti_prm.c b/sys/arm/ti/ti_prm.c new file mode 100644 index 000000000000..4a57fbb8b972 --- /dev/null +++ b/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); diff --git a/sys/arm/ti/ti_prm.h b/sys/arm/ti/ti_prm.h new file mode 100644 index 000000000000..bc3e991088f0 --- /dev/null +++ b/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__ */ diff --git a/sys/arm/ti/ti_pruss.c b/sys/arm/ti/ti_pruss.c index 48c6b17f3ac8..a8dc15ab80b0 100644 --- a/sys/arm/ti/ti_pruss.c +++ b/sys/arm/ti/ti_pruss.c @@ -57,8 +57,11 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include + +#include #include +#include #ifdef DEBUG #define DPRINTF(fmt, ...) do { \ @@ -161,7 +164,8 @@ static driver_t ti_pruss_driver = { 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 @@ static int 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); @@ -602,6 +681,9 @@ ti_pruss_attach(device_t dev) } } + 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"); diff --git a/sys/arm/ti/ti_scm.c b/sys/arm/ti/ti_scm.c index fbc87eeb4f92..896a8d09cbf3 100644 --- a/sys/arm/ti/ti_scm.c +++ b/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. + * 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$ */ -/** - * SCM - System Control Module - * - * Hopefully in the end this module will contain a bunch of utility functions - * for configuring and querying the general system control registers, but for - * now it only does pin(pad) multiplexing. - * - * This is different from the GPIO module in that it is used to configure the - * pins between modules not just GPIO input/output. - * - * This file contains the generic top level driver, however it relies on chip - * specific settings and therefore expects an array of ti_scm_padconf structs - * call ti_padconf_devmap to be located somewhere in the kernel. - * - */ #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]); - - ti_scm_sc = sc; - - /* Attach platform extensions, if any. */ - bus_generic_probe(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)); } -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); + diff --git a/sys/arm/ti/ti_scm_syscon.c b/sys/arm/ti/ti_scm_syscon.c new file mode 100644 index 000000000000..2c3fa9345210 --- /dev/null +++ b/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); diff --git a/sys/arm/ti/ti_sdhci.c b/sys/arm/ti/ti_sdhci.c index a76453d92588..4d19f4663d2f 100644 --- a/sys/arm/ti/ti_sdhci.c +++ b/sys/arm/ti/ti_sdhci.c @@ -44,10 +44,11 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include -#include +#include +#include +#include "gpio_if.h" +#include #include #include @@ -59,10 +60,10 @@ __FBSDID("$FreeBSD$"); #include #include "sdhci_if.h" -#include -#include -#include -#include "gpio_if.h" +#include +#include +#include + #include "opt_mmccam.h" @@ -73,10 +74,9 @@ struct ti_sdhci_softc { 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,24 +414,32 @@ ti_sdhci_detach(device_t dev) 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 */ @@ -499,6 +507,8 @@ ti_sdhci_hw_init(device_t dev) /* 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 @@ ti_sdhci_attach(device_t dev) 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 @@ ti_sdhci_attach(device_t dev) * 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 @@ ti_sdhci_attach(device_t dev) 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 @@ static driver_t ti_sdhci_driver = { 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 diff --git a/sys/arm/ti/ti_sdma.c b/sys/arm/ti/ti_sdma.c index b5c47a109b6f..3df674a33dcd 100644 --- a/sys/arm/ti/ti_sdma.c +++ b/sys/arm/ti/ti_sdma.c @@ -51,7 +51,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include +#include #include #include @@ -79,7 +79,7 @@ __FBSDID("$FreeBSD$"); */ 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 ti_sdma_softc { 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 @@ struct ti_sdma_softc { /* 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 @@ ti_sdma_intr(void *arg) 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 @@ ti_sdma_attach(device_t dev) 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 @@ ti_sdma_attach(device_t dev) } } - /* + /* * Install interrupt handlers for the for possible interrupts. Any channel * can trip one of the four IRQs */ @@ -1248,4 +1249,4 @@ static driver_t ti_sdma_driver = { 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); diff --git a/sys/arm/ti/ti_spi.c b/sys/arm/ti/ti_spi.c index a424f36b8683..19b80605b9b6 100644 --- a/sys/arm/ti/ti_spi.c +++ b/sys/arm/ti/ti_spi.c @@ -48,8 +48,7 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include +#include #include #include @@ -166,28 +165,15 @@ ti_spi_probe(device_t dev) 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 @@ ti_spi_attach(device_t dev) } /* 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 @@ static driver_t ti_spi_driver = { }; DRIVER_MODULE(ti_spi, simplebus, ti_spi_driver, ti_spi_devclass, 0, 0); +MODULE_DEPEND(ti_spi, ti_sysc, 1, 1, 1); diff --git a/sys/arm/ti/ti_sysc.c b/sys/arm/ti/ti_sysc.c index d428dd44a1ab..171520643c13 100644 --- a/sys/arm/ti/ti_sysc.c +++ b/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 @@ __FBSDID("$FreeBSD$"); #include #include #include +#include #include #include #include @@ -47,20 +50,401 @@ __FBSDID("$FreeBSD$"); #include #include -static struct ofw_compat_data compat_data[] = { - { "ti,sysc", 1 }, - { NULL, 0 } -}; +#include -struct ti_sysc_softc { - struct simplebus_softc sc; - device_t dev; -}; +#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-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; +}; + +/* + * 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) { @@ -71,8 +455,6 @@ ti_sysc_probe(device_t dev) return (ENXIO); device_set_desc(dev, "TI SYSC Interconnect"); - if (!bootverbose) - device_quiet(dev); return (BUS_PROBE_DEFAULT); } @@ -81,48 +463,160 @@ static int 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); diff --git a/sys/arm/ti/ti_sysc.h b/sys/arm/ti/ti_sysc.h new file mode 100644 index 000000000000..b74222f05772 --- /dev/null +++ b/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__ */ diff --git a/sys/arm/ti/ti_wdt.c b/sys/arm/ti/ti_wdt.c index 539e4d93950f..29ae41eac531 100644 --- a/sys/arm/ti/ti_wdt.c +++ b/sys/arm/ti/ti_wdt.c @@ -49,7 +49,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #ifdef DEBUG @@ -93,6 +92,7 @@ static driver_t ti_wdt_driver = { 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) diff --git a/sys/arm/ti/usb/omap_ehci.c b/sys/arm/ti/usb/omap_ehci.c index c14a483b7175..adc2c122f054 100644 --- a/sys/arm/ti/usb/omap_ehci.c +++ b/sys/arm/ti/usb/omap_ehci.c @@ -57,7 +57,6 @@ __FBSDID("$FreeBSD$"); #include -#include #include #include diff --git a/sys/arm/ti/usb/omap_host.c b/sys/arm/ti/usb/omap_host.c index 304e80d33df8..736ccf17262e 100644 --- a/sys/arm/ti/usb/omap_host.c +++ b/sys/arm/ti/usb/omap_host.c @@ -40,7 +40,7 @@ __FBSDID("$FreeBSD$"); #include -#include +#include #include /* @@ -139,12 +139,14 @@ omap_uhh_init(struct omap_uhh_softc *isc) 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 @@ omap_uhh_init(struct omap_uhh_softc *isc) 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 @@ omap_uhh_fini(struct omap_uhh_softc *isc) } /* 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"); } diff --git a/sys/arm/ti/usb/omap_tll.c b/sys/arm/ti/usb/omap_tll.c index eb3e246a61d6..c5383e3d52d3 100644 --- a/sys/arm/ti/usb/omap_tll.c +++ b/sys/arm/ti/usb/omap_tll.c @@ -39,7 +39,7 @@ __FBSDID("$FreeBSD$"); #include -#include +#include #include /* @@ -212,7 +212,7 @@ omap_tll_init(struct omap_tll_softc *sc) 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 @@ omap_tll_init(struct omap_tll_softc *sc) 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 @@ omap_tll_disable(struct omap_tll_softc *sc) } /* 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 diff --git a/sys/dev/uart/uart_dev_ti8250.c b/sys/dev/uart/uart_dev_ti8250.c index f5a230908da3..ebe777ed7fdb 100644 --- a/sys/dev/uart/uart_dev_ti8250.c +++ b/sys/dev/uart/uart_dev_ti8250.c @@ -39,9 +39,6 @@ __FBSDID("$FreeBSD$"); #include #include -#include -#include - #include #include #include @@ -52,6 +49,8 @@ __FBSDID("$FreeBSD$"); #include #include +#include + #include "uart_if.h" /* @@ -74,16 +73,8 @@ static int 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); /* diff --git a/sys/modules/Makefile b/sys/modules/Makefile index dff871fa7338..dc4e04736670 100644 --- a/sys/modules/Makefile +++ b/sys/modules/Makefile @@ -755,7 +755,7 @@ _pst= pst _sbni= sbni .endif -.if ${MACHINE_CPUARCH} == "arm" +.if ${MACHINE_ARCH} == "armv7" _cfi= cfi _cpsw= cpsw .endif