aboutsummaryrefslogtreecommitdiff
path: root/sys/arm/ti
diff options
context:
space:
mode:
Diffstat (limited to 'sys/arm/ti')
-rw-r--r--sys/arm/ti/am335x/am3359_cppi41.c192
-rw-r--r--sys/arm/ti/am335x/am335x_dmtimer.c84
-rw-r--r--sys/arm/ti/am335x/am335x_dmtpps.c114
-rw-r--r--sys/arm/ti/am335x/am335x_dmtreg.h12
-rw-r--r--sys/arm/ti/am335x/am335x_gpio.c1
-rw-r--r--sys/arm/ti/am335x/am335x_lcd.c33
-rw-r--r--sys/arm/ti/am335x/am335x_musb.c71
-rw-r--r--sys/arm/ti/am335x/am335x_prcm.c884
-rw-r--r--sys/arm/ti/am335x/am335x_pwmss.c68
-rw-r--r--sys/arm/ti/am335x/am335x_rtc.c6
-rw-r--r--sys/arm/ti/am335x/am335x_scm.c44
-rw-r--r--sys/arm/ti/am335x/am335x_usb_phy.c121
-rw-r--r--sys/arm/ti/am335x/am335x_usbss.c226
-rw-r--r--sys/arm/ti/am335x/files.am335x4
-rw-r--r--sys/arm/ti/clk/clock_common.c152
-rw-r--r--sys/arm/ti/clk/clock_common.h43
-rw-r--r--sys/arm/ti/clk/ti_clk_clkctrl.c219
-rw-r--r--sys/arm/ti/clk/ti_clk_clkctrl.h43
-rw-r--r--sys/arm/ti/clk/ti_clk_dpll.c341
-rw-r--r--sys/arm/ti/clk/ti_clk_dpll.h97
-rw-r--r--sys/arm/ti/clk/ti_clkctrl.c353
-rw-r--r--sys/arm/ti/clk/ti_divider_clock.c264
-rw-r--r--sys/arm/ti/clk/ti_dpll_clock.c375
-rw-r--r--sys/arm/ti/clk/ti_gate_clock.c266
-rw-r--r--sys/arm/ti/clk/ti_mux_clock.c249
-rw-r--r--sys/arm/ti/cpsw/if_cpsw.c28
-rw-r--r--sys/arm/ti/files.ti13
-rw-r--r--sys/arm/ti/omap4/files.omap42
-rw-r--r--sys/arm/ti/ti_adc.c7
-rw-r--r--sys/arm/ti/ti_edma3.c13
-rw-r--r--sys/arm/ti/ti_gpio.c82
-rw-r--r--sys/arm/ti/ti_hwmods.c214
-rw-r--r--sys/arm/ti/ti_hwmods.h37
-rw-r--r--sys/arm/ti/ti_i2c.c20
-rw-r--r--sys/arm/ti/ti_mbox.c9
-rw-r--r--sys/arm/ti/ti_omap4_cm.c151
-rw-r--r--sys/arm/ti/ti_omap4_cm.h34
-rw-r--r--sys/arm/ti/ti_pinmux.c2
-rw-r--r--sys/arm/ti/ti_prcm.c534
-rw-r--r--sys/arm/ti/ti_prcm.h208
-rw-r--r--sys/arm/ti/ti_prm.c210
-rw-r--r--sys/arm/ti/ti_prm.h38
-rw-r--r--sys/arm/ti/ti_pruss.c96
-rw-r--r--sys/arm/ti/ti_scm.c205
-rw-r--r--sys/arm/ti/ti_scm_syscon.c294
-rw-r--r--sys/arm/ti/ti_sdhci.c63
-rw-r--r--sys/arm/ti/ti_sdma.c19
-rw-r--r--sys/arm/ti/ti_spi.c24
-rw-r--r--sys/arm/ti/ti_sysc.c534
-rw-r--r--sys/arm/ti/ti_sysc.h43
-rw-r--r--sys/arm/ti/ti_wdt.c2
-rw-r--r--sys/arm/ti/usb/omap_ehci.c1
-rw-r--r--sys/arm/ti/usb/omap_host.c9
-rw-r--r--sys/arm/ti/usb/omap_tll.c8
54 files changed, 4991 insertions, 2171 deletions
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 <manu@FreeBSD.org>
+ *
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_sysc.h>
+
+#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 <machine/machdep.h> /* For arm_set_delay */
+#include <dev/extres/clk/clk.h>
+
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_hwmods.h>
+#include <arm/ti/ti_sysc.h>
#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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+#include "opt_platform.h"
+
#include <sys/param.h>
#include <sys/systm.h>
#include <sys/bus.h>
@@ -60,9 +62,9 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/extres/clk/clk.h>
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_hwmods.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/ti_pinmux.h>
#include <arm/ti/am335x/am335x_scm_padconf.h>
@@ -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 <machine/bus.h>
+#include <dev/extres/clk/clk.h>
+
#include <dev/fdt/fdt_common.h>
#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
@@ -65,7 +67,7 @@ __FBSDID("$FreeBSD$");
#include <dev/vt/vt.h>
#endif
-#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/ti_scm.h>
#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 <sys/rman.h>
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_scm.h>
#include <arm/ti/am335x/am335x_scm.h>
+#include <arm/ti/ti_sysc.h>
+#include <dev/extres/clk/clk.h>
+#include <dev/extres/syscon/syscon.h>
+#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;
+
+ 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 */
- 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);
+ 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 <dmarion@Freebsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-#include <sys/module.h>
-#include <sys/malloc.h>
-#include <sys/rman.h>
-#include <sys/timeet.h>
-#include <sys/timetc.h>
-#include <sys/watchdog.h>
-#include <machine/bus.h>
-#include <machine/cpu.h>
-#include <machine/intr.h>
-
-#include <arm/ti/tivar.h>
-#include <arm/ti/ti_scm.h>
-#include <arm/ti/ti_prcm.h>
-
-#include <dev/ofw/openfirm.h>
-#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_bus_subr.h>
-
-#include <machine/bus.h>
-
-#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 <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_hwmods.h>
-#include <arm/ti/ti_scm.h>
+#include <arm/ti/ti_sysc.h>
+
+#include <dev/extres/syscon/syscon.h>
+#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, &reg);
- switch (sc->sc_clk) {
- case PWMSS0_CLK:
- id = 0;
- break;
- case PWMSS1_CLK:
- id = 1;
- break;
-
- case PWMSS2_CLK:
- id = 2;
- break;
- default:
- device_printf(dev, "unknown pwmss clock id: %d\n", sc->sc_clk);
- return (EINVAL);
+ ti_sysc_clock_enable(device_get_parent(dev));
+
+ 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 <machine/bus.h>
+#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/am335x/am335x_rtcvar.h>
#include <arm/ti/am335x/am335x_rtcreg.h>
@@ -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 <arm/ti/ti_cpuid.h>
#include <arm/ti/ti_scm.h>
+#include <dev/extres/syscon/syscon.h>
+#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);
+ 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, &reg);
+ 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, &reg);
+ 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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/fbio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/resource.h>
+#include <machine/bus.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#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 <gonzo@freebsd.org>
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
- * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
- * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
- * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
- * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
- * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
- * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
- * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
- * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
- * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
- * SUCH DAMAGE.
- */
-
-#include <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/stdint.h>
-#include <sys/stddef.h>
-#include <sys/param.h>
-#include <sys/queue.h>
-#include <sys/types.h>
-#include <sys/systm.h>
-#include <sys/kernel.h>
-#include <sys/bus.h>
-#include <sys/module.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-#include <sys/condvar.h>
-#include <sys/sysctl.h>
-#include <sys/sx.h>
-#include <sys/unistd.h>
-#include <sys/callout.h>
-#include <sys/malloc.h>
-#include <sys/priv.h>
-
-#include <dev/fdt/simplebus.h>
-#include <dev/ofw/openfirm.h>
-#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_bus_subr.h>
-
-#include <dev/usb/usb.h>
-#include <dev/usb/usbdi.h>
-
-#include <dev/usb/usb_core.h>
-#include <dev/usb/usb_busdma.h>
-#include <dev/usb/usb_process.h>
-#include <dev/usb/usb_util.h>
-
-#include <dev/usb/usb_controller.h>
-#include <dev/usb/usb_bus.h>
-#include <dev/usb/controller/musb_otg.h>
-#include <dev/usb/usb_debug.h>
-
-#include <sys/rman.h>
-
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_scm.h>
-#include <arm/ti/am335x/am335x_scm.h>
-
-#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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/libkern.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk_mux.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/malloc.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <arm/ti/clk/ti_clk_clkctrl.h>
+
+#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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <dev/extres/clk/clk.h>
+
+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 <manu@freebsd.org>
+ *
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+
+#include <dev/extres/clk/clk.h>
+
+#include <arm/ti/clk/ti_clk_dpll.h>
+
+#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 <manu@freebsd.org>
+ *
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ *
+ * 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 <dev/extres/clk/clk.h>
+
+/* 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 <mmel@FreeBSD.org>
+ *
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/fbio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/resource.h>
+#include <machine/bus.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/clk/ti_clk_clkctrl.h>
+#include <arm/ti/ti_omap4_cm.h>
+#include <arm/ti/ti_cpuid.h>
+
+#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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/libkern.h>
+
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk_div.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/libkern.h>
+
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk_div.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/clk/ti_clk_dpll.h>
+#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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/libkern.h>
+
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk_gate.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/conf.h>
+#include <sys/bus.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/systm.h>
+#include <sys/libkern.h>
+#include <sys/types.h>
+#include <sys/malloc.h>
+
+#include <machine/bus.h>
+#include <dev/fdt/simplebus.h>
+
+#include <dev/extres/clk/clk_mux.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#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 <net/if_media.h>
#include <net/if_types.h>
-#include <arm/ti/ti_scm.h>
+#include <dev/extres/syscon/syscon.h>
+#include "syscon_if.h"
#include <arm/ti/am335x/am335x_scm.h>
#include <dev/mii/mii.h>
@@ -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);
+ 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);
+ 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 <dev/evdev/evdev.h>
#endif
-#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/ti_adcreg.h>
#include <arm/ti/ti_adcvar.h>
@@ -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 <dev/ofw/ofw_bus_subr.h>
#include <arm/ti/ti_scm.h>
-#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/ti_edma3.h>
@@ -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 <arm/ti/ti_cpuid.h>
#include <arm/ti/ti_gpio.h>
#include <arm/ti/ti_scm.h>
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_hwmods.h>
+#include <arm/ti/ti_sysc.h>
#include <dev/gpio/gpiobusvar.h>
#include <dev/ofw/openfirm.h>
@@ -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 <gonzo@freebsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 <sys/cdefs.h>
-__FBSDID("$FreeBSD$");
-
-#include <sys/param.h>
-#include <sys/systm.h>
-#include <sys/bus.h>
-#include <sys/kernel.h>
-
-#include <dev/ofw/openfirm.h>
-#include <dev/ofw/ofw_bus.h>
-#include <dev/ofw/ofw_bus_subr.h>
-
-#include <machine/bus.h>
-#include <machine/fdt.h>
-
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_hwmods.h>
-
-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 <gonzo@freebsd.org>
- * All rights reserved.
- *
- * Redistribution and use in source and binary forms, with or without
- * modification, are permitted provided that the following conditions
- * are met:
- * 1. Redistributions of source code must retain the above copyright
- * notice, this list of conditions and the following disclaimer.
- * 2. Redistributions in binary form must reproduce the above copyright
- * notice, this list of conditions and the following disclaimer in the
- * documentation and/or other materials provided with the distribution.
- *
- * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``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 <dev/ofw/ofw_bus_subr.h>
#include <arm/ti/ti_cpuid.h>
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_hwmods.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/ti_i2c.h>
#include <dev/iicbus/iiconf.h>
@@ -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 <machine/bus.h>
#include <arm/ti/ti_mbox.h>
-#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sysc.h>
#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 <manu@FreeBSD.org>
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/fbio.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/rman.h>
+#include <sys/resource.h>
+#include <machine/bus.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_omap4_cm.h>
+
+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 <oskar.holmlund@ohdata.se>
+ *
+ * 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,10 +1,11 @@
/*-
- * SPDX-License-Identifier: BSD-4-Clause
+ * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
*
- * Copyright (c) 2010
- * Ben Gray <ben.r.gray@gmail.com>.
+ * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
* All rights reserved.
*
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ *
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
@@ -13,345 +14,332 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Ben Gray.
- * 4. The name of the company nor the name of the author may be used to
- * endorse or promote products derived from this software without specific
- * prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * Power, Reset and Clock Management Module
- *
- * 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.
+ * 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/bus.h>
#include <sys/kernel.h>
#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/resource.h>
+#include <sys/malloc.h>
#include <sys/rman.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-
+#include <sys/timeet.h>
+#include <sys/timetc.h>
+#include <sys/watchdog.h>
#include <machine/bus.h>
-#include <machine/resource.h>
+#include <machine/cpu.h>
#include <machine/intr.h>
#include <arm/ti/ti_cpuid.h>
#include <arm/ti/ti_prcm.h>
+#include <arm/ti/tivar.h>
-/**
- * ti_*_clk_devmap - Array of clock devices, should be defined one per SoC
- *
- * This array is typically defined in one of the targeted *_prcm_clk.c
- * files and is specific to the given SoC platform. Each entry in the array
- * corresponds to an individual clock device.
- */
-extern struct ti_clock_dev ti_omap4_clk_devmap[];
-extern struct ti_clock_dev ti_am335x_clk_devmap[];
+#include <dev/fdt/simplebus.h>
-/**
- * ti_prcm_clk_dev - returns a pointer to the clock device with given id
- * @clk: the ID of the clock device to get
- *
- * Simply iterates through the clk_devmap global array and returns a pointer
- * to the clock device if found.
- *
- * LOCKING:
- * None
- *
- * RETURNS:
- * The pointer to the clock device on success, on failure NULL is returned.
- */
-static struct ti_clock_dev *
-ti_prcm_clk_dev(clk_ident_t clk)
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "clkdev_if.h"
+
+#if 0
+#define DPRINTF(dev, msg...) device_printf(dev, msg)
+#else
+#define DPRINTF(dev, msg...)
+#endif
+
+struct ti_prcm_softc {
+ struct simplebus_softc sc_simplebus;
+ device_t dev;
+ struct resource * mem_res;
+ bus_space_tag_t bst;
+ bus_space_handle_t bsh;
+ int attach_done;
+ struct mtx mtx;
+};
+
+static struct ti_prcm_softc *ti_prcm_sc = NULL;
+static void omap4_prcm_reset(void);
+static void am335x_prcm_reset(void);
+
+#define TI_AM3_PRCM 18
+#define TI_AM4_PRCM 17
+#define TI_OMAP2_PRCM 16
+#define TI_OMAP3_PRM 15
+#define TI_OMAP3_CM 14
+#define TI_OMAP4_CM1 13
+#define TI_OMAP4_PRM 12
+#define TI_OMAP4_CM2 11
+#define TI_OMAP4_SCRM 10
+#define TI_OMAP5_PRM 9
+#define TI_OMAP5_CM_CORE_AON 8
+#define TI_OMAP5_SCRM 7
+#define TI_OMAP5_CM_CORE 6
+#define TI_DRA7_PRM 5
+#define TI_DRA7_CM_CORE_AON 4
+#define TI_DRA7_CM_CORE 3
+#define TI_DM814_PRCM 2
+#define TI_DM816_PRCM 1
+#define TI_PRCM_END 0
+
+static struct ofw_compat_data compat_data[] = {
+ { "ti,am3-prcm", TI_AM3_PRCM },
+ { "ti,am4-prcm", TI_AM4_PRCM },
+ { "ti,omap2-prcm", TI_OMAP2_PRCM },
+ { "ti,omap3-prm", TI_OMAP3_PRM },
+ { "ti,omap3-cm", TI_OMAP3_CM },
+ { "ti,omap4-cm1", TI_OMAP4_CM1 },
+ { "ti,omap4-prm", TI_OMAP4_PRM },
+ { "ti,omap4-cm2", TI_OMAP4_CM2 },
+ { "ti,omap4-scrm", TI_OMAP4_SCRM },
+ { "ti,omap5-prm", TI_OMAP5_PRM },
+ { "ti,omap5-cm-core-aon", TI_OMAP5_CM_CORE_AON },
+ { "ti,omap5-scrm", TI_OMAP5_SCRM },
+ { "ti,omap5-cm-core", TI_OMAP5_CM_CORE },
+ { "ti,dra7-prm", TI_DRA7_PRM },
+ { "ti,dra7-cm-core-aon", TI_DRA7_CM_CORE_AON },
+ { "ti,dra7-cm-core", TI_DRA7_CM_CORE },
+ { "ti,dm814-prcm", TI_DM814_PRCM },
+ { "ti,dm816-prcm", TI_DM816_PRCM },
+ { NULL, TI_PRCM_END}
+};
+
+static int
+ti_prcm_probe(device_t dev)
{
- struct ti_clock_dev *clk_dev;
-
- /* Find the clock within the devmap - it's a bit inefficent having a for
- * loop for this, but this function should only called when a driver is
- * being activated so IMHO not a big issue.
+ if (!ofw_bus_status_okay(dev))
+ return (ENXIO);
+
+ if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) {
+ return (ENXIO);
+ }
+
+ device_set_desc(dev, "TI Power and Clock Management");
+ return(BUS_PROBE_DEFAULT);
+}
+
+static int
+ti_prcm_attach(device_t dev)
+{
+ struct ti_prcm_softc *sc;
+ phandle_t node, child;
+ int rid;
+
+ sc = device_get_softc(dev);
+ sc->dev = dev;
+
+ node = ofw_bus_get_node(sc->dev);
+ simplebus_init(sc->dev, node);
+
+ if (simplebus_fill_ranges(node, &sc->sc_simplebus) < 0) {
+ device_printf(sc->dev, "could not get ranges\n");
+ return (ENXIO);
+ }
+ if (sc->sc_simplebus.nranges == 0) {
+ device_printf(sc->dev, "nranges == 0\n");
+ return (ENXIO);
+ }
+
+ sc->mem_res = bus_alloc_resource(sc->dev, SYS_RES_MEMORY, &rid,
+ sc->sc_simplebus.ranges[0].host,
+ (sc->sc_simplebus.ranges[0].host +
+ sc->sc_simplebus.ranges[0].size - 1),
+ sc->sc_simplebus.ranges[0].size,
+ RF_ACTIVE | RF_SHAREABLE);
+
+ if (sc->mem_res == NULL) {
+ return (ENXIO);
+ }
+
+ sc->bst = rman_get_bustag(sc->mem_res);
+ sc->bsh = rman_get_bushandle(sc->mem_res);
+
+ mtx_init(&sc->mtx, device_get_nameunit(dev), NULL, MTX_DEF);
+
+ /* Fixme: for xxx_prcm_reset functions.
+ * Get rid of global variables?
*/
- clk_dev = NULL;
+ ti_prcm_sc = sc;
+
switch(ti_chip()) {
#ifdef SOC_OMAP4
case CHIP_OMAP_4:
- clk_dev = &(ti_omap4_clk_devmap[0]);
+ ti_cpu_reset = omap4_prcm_reset;
break;
#endif
#ifdef SOC_TI_AM335X
case CHIP_AM335X:
- clk_dev = &(ti_am335x_clk_devmap[0]);
+ ti_cpu_reset = am335x_prcm_reset;
break;
#endif
}
- if (clk_dev == NULL)
- panic("No clock devmap found");
- while (clk_dev->id != INVALID_CLK_IDENT) {
- if (clk_dev->id == clk) {
- return (clk_dev);
- }
- clk_dev++;
+
+ bus_generic_probe(sc->dev);
+ for (child = OF_child(node); child != 0; child = OF_peer(child)) {
+ simplebus_add_device(dev, child, 0, NULL, -1, NULL);
}
- /* Sanity check we managed to find the clock */
- printf("ti_prcm: Failed to find clock device (%d)\n", clk);
- return (NULL);
+ return (bus_generic_attach(sc->dev));
}
-/**
- * ti_prcm_clk_valid - enables a clock for a particular module
- * @clk: identifier for the module to enable, see ti_prcm.h for a list
- * of possible modules.
- * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
- *
- * This function can enable either a functional or interface clock.
- *
- * The real work done to enable the clock is really done in the callback
- * function associated with the clock, this function is simply a wrapper
- * around that.
- *
- * LOCKING:
- * Internally locks the driver context.
- *
- * RETURNS:
- * Returns 0 on success or positive error code on failure.
- */
int
-ti_prcm_clk_valid(clk_ident_t clk)
+ti_prcm_write_4(device_t dev, bus_addr_t addr, uint32_t val)
{
- int ret = 0;
+ struct ti_prcm_softc *sc;
- if (ti_prcm_clk_dev(clk) == NULL)
- ret = EINVAL;
-
- return (ret);
+ sc = device_get_softc(dev);
+ DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val);
+ bus_space_write_4(sc->bst, sc->bsh, addr, val);
+ return (0);
}
+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);
+}
-/**
- * ti_prcm_clk_enable - enables a clock for a particular module
- * @clk: identifier for the module to enable, see ti_prcm.h for a list
- * of possible modules.
- * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
- *
- * This function can enable either a functional or interface clock.
- *
- * The real work done to enable the clock is really done in the callback
- * function associated with the clock, this function is simply a wrapper
- * around that.
- *
- * LOCKING:
- * Internally locks the driver context.
- *
- * RETURNS:
- * Returns 0 on success or positive error code on failure.
- */
int
-ti_prcm_clk_enable(clk_ident_t clk)
+ti_prcm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set)
{
- 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);
+ struct ti_prcm_softc *sc;
+ uint32_t reg;
- /* Sanity check we managed to find the clock */
- if (clk_dev == NULL)
- return (EINVAL);
+ sc = device_get_softc(dev);
- /* Activate the clock */
- if (clk_dev->clk_activate)
- ret = clk_dev->clk_activate(clk_dev);
- else
- ret = EINVAL;
+ reg = bus_space_read_4(sc->bst, sc->bsh, addr);
+ reg &= ~clr;
+ reg |= set;
+ bus_space_write_4(sc->bst, sc->bsh, addr, reg);
+ DPRINTF(sc->dev, "offset=%lx reg: %x (clr %x set %x)\n", addr, reg, clr, set);
- return (ret);
+ return (0);
}
-
-/**
- * ti_prcm_clk_disable - disables a clock for a particular module
- * @clk: identifier for the module to enable, see ti_prcm.h for a list
- * of possible modules.
- * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
- *
- * This function can enable either a functional or interface clock.
- *
- * The real work done to enable the clock is really done in the callback
- * function associated with the clock, this function is simply a wrapper
- * around that.
- *
- * LOCKING:
- * Internally locks the driver context.
- *
- * RETURNS:
- * Returns 0 on success or positive error code on failure.
- */
-int
-ti_prcm_clk_disable(clk_ident_t clk)
+void
+ti_prcm_device_lock(device_t dev)
{
- struct ti_clock_dev *clk_dev;
- int ret;
+ struct ti_prcm_softc *sc;
- /* Find the clock within the devmap - it's a bit inefficent having a for
- * loop for this, but this function should only called when a driver is
- * being activated so IMHO not a big issue.
- */
- clk_dev = ti_prcm_clk_dev(clk);
-
- /* 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);
+ sc = device_get_softc(dev);
+ mtx_lock(&sc->mtx);
}
-/**
- * ti_prcm_clk_set_source - sets the source
- * @clk: identifier for the module to enable, see ti_prcm.h for a list
- * of possible modules.
- * Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK.
- *
- * This function can enable either a functional or interface clock.
- *
- * The real work done to enable the clock is really done in the callback
- * function associated with the clock, this function is simply a wrapper
- * around that.
- *
- * LOCKING:
- * Internally locks the driver context.
- *
- * RETURNS:
- * Returns 0 on success or positive error code on failure.
- */
-int
-ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc)
+void
+ti_prcm_device_unlock(device_t dev)
{
- struct ti_clock_dev *clk_dev;
- int ret;
+ struct ti_prcm_softc *sc;
- /* Find the clock within the devmap - it's a bit inefficent having a for
- * loop for this, but this function should only called when a driver is
- * being activated so IMHO not a big issue.
- */
- clk_dev = ti_prcm_clk_dev(clk);
+ sc = device_get_softc(dev);
+ mtx_unlock(&sc->mtx);
+}
- /* Sanity check we managed to find the clock */
- if (clk_dev == NULL)
- return (EINVAL);
+static device_method_t ti_prcm_methods[] = {
+ DEVMETHOD(device_probe, ti_prcm_probe),
+ DEVMETHOD(device_attach, ti_prcm_attach),
- /* Activate the clock */
- if (clk_dev->clk_set_source)
- ret = clk_dev->clk_set_source(clk_dev, clksrc);
- else
- ret = EINVAL;
+ /* 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),
- return (ret);
-}
+ DEVMETHOD_END
+};
+DEFINE_CLASS_1(ti_prcm, ti_prcm_driver, ti_prcm_methods,
+ sizeof(struct ti_prcm_softc), simplebus_driver);
-/**
- * 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;
+static devclass_t ti_prcm_devclass;
- /* 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);
+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);
- /* 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;
+/* From sys/arm/ti/am335x/am335x_prcm.c
+ * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org>
+ */
+#define PRM_DEVICE_OFFSET 0xF00
+#define AM335x_PRM_RSTCTRL (PRM_DEVICE_OFFSET + 0x00)
- return (ret);
+static void
+am335x_prcm_reset(void)
+{
+ ti_prcm_write_4(ti_prcm_sc->dev, AM335x_PRM_RSTCTRL, (1<<1));
}
-/**
- * ti_prcm_clk_set_source_freq - sets the source clock frequency as close to freq as possible
- * @clk: identifier for the module to enable, see ti_prcm.h for a list
- * of possible modules.
- * @freq: requested freq
+/* FIXME: Is this correct - or should the license part be ontop? */
+
+/* From sys/arm/ti/omap4/omap4_prcm_clks.c */
+/*-
+ * SPDX-License-Identifier: BSD-3-Clause
*
- * LOCKING:
- * Internally locks the driver context.
+ * Copyright (c) 2011
+ * Ben Gray <ben.r.gray@gmail.com>.
+ * All rights reserved.
*
- * RETURNS:
- * Returns 0 on success or positive error code on failure.
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the company nor the name of the author may be used to
+ * endorse or promote products derived from this software without specific
+ * prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
+ * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+ * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
+ * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
+ * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
-int
-ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq)
-{
- struct ti_clock_dev *clk_dev;
- int ret;
+#define PRM_RSTCTRL 0x1b00
+#define PRM_RSTCTRL_RESET 0x2
- 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;
+static void
+omap4_prcm_reset(void)
+{
+ uint32_t reg;
- return (ret);
+ ti_prcm_read_4(ti_prcm_sc->dev, PRM_RSTCTRL, &reg);
+ 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, &reg);
}
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 <ben.r.gray@gmail.com>.
- * All rights reserved.
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
*
* 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_
-
-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);
+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);
-#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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_prm.h>
+
+#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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-#include <arm/ti/ti_prcm.h>
+#include <dev/extres/clk/clk.h>
+
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/ti_pruss.h>
+#include <arm/ti/ti_prm.h>
#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 <manu@FreeBSD.org>
*
- * Copyright (c) 2010
- * Ben Gray <ben.r.gray@gmail.com>.
- * All rights reserved.
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
@@ -13,169 +11,152 @@
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in the
* documentation and/or other materials provided with the distribution.
- * 3. All advertising materials mentioning features or use of this software
- * must display the following acknowledgement:
- * This product includes software developed by Ben Gray.
- * 4. The name of the company nor the name of the author may be used to
- * endorse or promote products derived from this software without specific
- * prior written permission.
*
- * THIS SOFTWARE IS PROVIDED BY BEN GRAY ``AS IS'' AND ANY EXPRESS OR
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
- * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
- * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
- * OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
- * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR
- * OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF
- * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- */
-
-/**
- * SCM - System Control Module
- *
- * 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.
+ * 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 <sys/cdefs.h>
__FBSDID("$FreeBSD$");
+
+/* Based on sys/arm/ti/ti_sysc.c */
+
#include <sys/param.h>
#include <sys/systm.h>
+#include <sys/bus.h>
+#include <sys/fbio.h>
#include <sys/kernel.h>
#include <sys/module.h>
-#include <sys/bus.h>
-#include <sys/resource.h>
#include <sys/rman.h>
-#include <sys/lock.h>
-#include <sys/mutex.h>
-
+#include <sys/resource.h>
#include <machine/bus.h>
-#include <machine/resource.h>
+#include <vm/vm.h>
+#include <vm/vm_extern.h>
+#include <vm/vm_kern.h>
+#include <vm/pmap.h>
+
+#include <dev/fdt/simplebus.h>
-#include <dev/ofw/openfirm.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
-#include <dev/fdt/fdt_pinctrl.h>
-
-#include "ti_scm.h"
-#include "ti_cpuid.h"
-static struct resource_spec ti_scm_res_spec[] = {
- { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Control memory window */
- { -1, 0 }
+#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 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)
-{
- if (!ti_scm_sc)
- return (ENXIO);
-
- *val = ti_scm_read_4(ti_scm_sc, reg);
- return (0);
-}
-
-int
-ti_scm_reg_write_4(uint32_t reg, uint32_t val)
+static int
+ti_scm_detach(device_t dev)
{
- if (!ti_scm_sc)
- return (ENXIO);
-
- ti_scm_write_4(ti_scm_sc, reg, val);
- return (0);
+ return (EBUSY);
}
-
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 <manu@FreeBSD.org>
+ *
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ *
+ * 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 <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/param.h>
+#include <sys/systm.h>
+#include <sys/kernel.h>
+#include <sys/module.h>
+#include <sys/bus.h>
+#include <sys/resource.h>
+#include <sys/rman.h>
+#include <sys/lock.h>
+#include <sys/mutex.h>
+
+#include <machine/bus.h>
+#include <machine/resource.h>
+
+#include <dev/fdt/simplebus.h>
+
+#include <dev/ofw/openfirm.h>
+#include <dev/ofw/ofw_bus.h>
+#include <dev/ofw/ofw_bus_subr.h>
+
+#include "syscon_if.h"
+#include <dev/extres/syscon/syscon.h>
+#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 <sys/lock.h>
#include <sys/mutex.h>
-#include <machine/bus.h>
-#include <machine/resource.h>
-#include <machine/intr.h>
+#include <arm/ti/ti_cpuid.h>
+#include <arm/ti/ti_sysc.h>
+#include "gpio_if.h"
+#include <dev/extres/clk/clk.h>
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
@@ -59,10 +60,10 @@ __FBSDID("$FreeBSD$");
#include <dev/sdhci/sdhci_fdt_gpio.h>
#include "sdhci_if.h"
-#include <arm/ti/ti_cpuid.h>
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_hwmods.h>
-#include "gpio_if.h"
+#include <machine/bus.h>
+#include <machine/resource.h>
+#include <machine/intr.h>
+
#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 <dev/ofw/ofw_bus_subr.h>
#include <arm/ti/ti_cpuid.h>
-#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/ti_sdma.h>
#include <arm/ti/ti_sdmareg.h>
@@ -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 <dev/spibus/spi.h>
#include <dev/spibus/spibusvar.h>
-#include <arm/ti/ti_prcm.h>
-#include <arm/ti/ti_hwmods.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/ti_spireg.h>
#include <arm/ti/ti_spivar.h>
@@ -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 <manu@FreeBSD.org>
*
+ * Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se>
+ *
* 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 <sys/fbio.h>
#include <sys/kernel.h>
#include <sys/module.h>
+#include <sys/queue.h>
#include <sys/rman.h>
#include <sys/resource.h>
#include <machine/bus.h>
@@ -47,21 +50,402 @@ __FBSDID("$FreeBSD$");
#include <dev/ofw/ofw_bus.h>
#include <dev/ofw/ofw_bus_subr.h>
+#include <dev/extres/clk/clk.h>
+
+#include <arm/ti/ti_sysc.h>
+#include <arm/ti/clk/clock_common.h>
+
+#define DEBUG_SYSC 0
+
+#if DEBUG_SYSC
+#define DPRINTF(dev, msg...) device_printf(dev, msg)
+#else
+#define DPRINTF(dev, msg...)
+#endif
+
+/* Documentation/devicetree/bindings/bus/ti-sysc.txt
+ *
+ * Documentation/devicetree/clock/clock-bindings.txt
+ * Defines phandle + optional pair
+ * Documentation/devicetree/clock/ti-clkctl.txt
+ */
+
+static int ti_sysc_probe(device_t dev);
+static int ti_sysc_attach(device_t dev);
+static int ti_sysc_detach(device_t dev);
+
+#define TI_SYSC_DRA7_MCAN 15
+#define TI_SYSC_USB_HOST_FS 14
+#define TI_SYSC_DRA7_MCASP 13
+#define TI_SYSC_MCASP 12
+#define TI_SYSC_OMAP_AES 11
+#define TI_SYSC_OMAP3_SHAM 10
+#define TI_SYSC_OMAP4_SR 9
+#define TI_SYSC_OMAP3630_SR 8
+#define TI_SYSC_OMAP3430_SR 7
+#define TI_SYSC_OMAP4_TIMER 6
+#define TI_SYSC_OMAP2_TIMER 5
+/* Above needs special workarounds */
+#define TI_SYSC_OMAP4_SIMPLE 4
+#define TI_SYSC_OMAP4 3
+#define TI_SYSC_OMAP2 2
+#define TI_SYSC 1
+#define TI_SYSC_END 0
+
static struct ofw_compat_data compat_data[] = {
- { "ti,sysc", 1 },
- { NULL, 0 }
+ { "ti,sysc-dra7-mcan", TI_SYSC_DRA7_MCAN },
+ { "ti,sysc-usb-host-fs", TI_SYSC_USB_HOST_FS },
+ { "ti,sysc-dra7-mcasp", TI_SYSC_DRA7_MCASP },
+ { "ti,sysc-mcasp", TI_SYSC_MCASP },
+ { "ti,sysc-omap-aes", TI_SYSC_OMAP_AES },
+ { "ti,sysc-omap3-sham", TI_SYSC_OMAP3_SHAM },
+ { "ti,sysc-omap4-sr", TI_SYSC_OMAP4_SR },
+ { "ti,sysc-omap3630-sr", TI_SYSC_OMAP3630_SR },
+ { "ti,sysc-omap3430-sr", TI_SYSC_OMAP3430_SR },
+ { "ti,sysc-omap4-timer", TI_SYSC_OMAP4_TIMER },
+ { "ti,sysc-omap2-timer", TI_SYSC_OMAP2_TIMER },
+ /* Above needs special workarounds */
+ { "ti,sysc-omap4-simple", TI_SYSC_OMAP4_SIMPLE },
+ { "ti,sysc-omap4", TI_SYSC_OMAP4 },
+ { "ti,sysc-omap2", TI_SYSC_OMAP2 },
+ { "ti,sysc", TI_SYSC },
+ { NULL, TI_SYSC_END }
+};
+
+/* reg-names can be "rev", "sysc" and "syss" */
+static const char * reg_names[] = { "rev", "sysc", "syss" };
+#define REG_REV 0
+#define REG_SYSC 1
+#define REG_SYSS 2
+#define REG_MAX 3
+
+/* master idle / slave idle mode defined in 8.1.3.2.1 / 8.1.3.2.2 */
+#include <gnu/dts/include/dt-bindings/bus/ti-sysc.h>
+#define SYSC_IDLE_MAX 4
+
+struct sysc_reg {
+ uint64_t address;
+ uint64_t size;
+};
+
+struct clk_list {
+ TAILQ_ENTRY(clk_list) next;
+ clk_t clk;
};
struct ti_sysc_softc {
struct simplebus_softc sc;
+ bool attach_done;
+
device_t dev;
+ int device_type;
+
+ struct sysc_reg reg[REG_MAX];
+ /* Offset from host base address */
+ uint64_t offset_reg[REG_MAX];
+
+ uint32_t ti_sysc_mask;
+ int32_t ti_sysc_midle[SYSC_IDLE_MAX];
+ int32_t ti_sysc_sidle[SYSC_IDLE_MAX];
+ uint32_t ti_sysc_delay_us;
+ uint32_t ti_syss_mask;
+
+ int num_clocks;
+ TAILQ_HEAD(, clk_list) clk_list;
+
+ /* deprecated ti_hwmods */
+ bool ti_no_reset_on_init;
+ bool ti_no_idle_on_init;
+ bool ti_no_idle;
};
-static int ti_sysc_probe(device_t dev);
-static int ti_sysc_attach(device_t dev);
-static int ti_sysc_detach(device_t dev);
+/*
+ * All sysc seems to have a reg["rev"] register.
+ * Lets use that for identification of which module the driver are connected to.
+ */
+uint64_t
+ti_sysc_get_rev_address(device_t dev) {
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+
+ return (sc->reg[REG_REV].address);
+}
+
+uint64_t
+ti_sysc_get_rev_address_offset_host(device_t dev) {
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+
+ return (sc->offset_reg[REG_REV]);
+}
+
+uint64_t
+ti_sysc_get_sysc_address(device_t dev) {
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+
+ return (sc->reg[REG_SYSC].address);
+}
+
+uint64_t
+ti_sysc_get_sysc_address_offset_host(device_t dev) {
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+
+ return (sc->offset_reg[REG_SYSC]);
+}
+
+uint64_t
+ti_sysc_get_syss_address(device_t dev) {
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+
+ return (sc->reg[REG_SYSS].address);
+}
+
+uint64_t
+ti_sysc_get_syss_address_offset_host(device_t dev) {
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+
+ return (sc->offset_reg[REG_SYSS]);
+}
+
+/*
+ * Due no memory region is assigned the sysc driver the children needs to
+ * handle the practical read/writes to the registers.
+ * Check if sysc has reset bit.
+ */
+uint32_t
+ti_sysc_get_soft_reset_bit(device_t dev) {
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+ switch (sc->device_type) {
+ case TI_SYSC_OMAP4_TIMER:
+ case TI_SYSC_OMAP4_SIMPLE:
+ case TI_SYSC_OMAP4:
+ if (sc->ti_sysc_mask & SYSC_OMAP4_SOFTRESET) {
+ return (SYSC_OMAP4_SOFTRESET);
+ }
+ break;
+
+ case TI_SYSC_OMAP2_TIMER:
+ case TI_SYSC_OMAP2:
+ case TI_SYSC:
+ if (sc->ti_sysc_mask & SYSC_OMAP2_SOFTRESET) {
+ return (SYSC_OMAP2_SOFTRESET);
+ }
+ break;
+ default:
+ break;
+ }
+
+ return (0);
+}
+
+int
+ti_sysc_clock_enable(device_t dev) {
+ struct clk_list *clkp, *clkp_tmp;
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+ int err;
+
+ TAILQ_FOREACH_SAFE(clkp, &sc->clk_list, next, clkp_tmp) {
+ err = clk_enable(clkp->clk);
+
+ if (err) {
+ DPRINTF(sc->dev, "clk_enable %s failed %d\n",
+ clk_get_name(clkp->clk), err);
+ break;
+ }
+ }
+ return (err);
+}
+
+int
+ti_sysc_clock_disable(device_t dev) {
+ struct clk_list *clkp, *clkp_tmp;
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+ int err = 0;
+
+ TAILQ_FOREACH_SAFE(clkp, &sc->clk_list, next, clkp_tmp) {
+ err = clk_disable(clkp->clk);
+
+ if (err) {
+ DPRINTF(sc->dev, "clk_enable %s failed %d\n",
+ clk_get_name(clkp->clk), err);
+ break;
+ }
+ }
+ return (err);
+}
static int
+parse_regfields(struct ti_sysc_softc *sc) {
+ phandle_t node;
+ uint32_t parent_address_cells;
+ uint32_t parent_size_cells;
+ cell_t *reg;
+ ssize_t nreg;
+ int err, k, reg_i, prop_idx;
+ uint32_t idx;
+
+ node = ofw_bus_get_node(sc->dev);
+
+ /* Get parents address and size properties */
+ err = OF_searchencprop(OF_parent(node), "#address-cells",
+ &parent_address_cells, sizeof(parent_address_cells));
+ if (err == -1)
+ return (ENXIO);
+ if (!(parent_address_cells == 1 || parent_address_cells == 2)) {
+ DPRINTF(sc->dev, "Expect parent #address-cells=[1||2]\n");
+ return (ENXIO);
+ }
+
+ err = OF_searchencprop(OF_parent(node), "#size-cells",
+ &parent_size_cells, sizeof(parent_size_cells));
+ if (err == -1)
+ return (ENXIO);
+
+ if (!(parent_size_cells == 1 || parent_size_cells == 2)) {
+ DPRINTF(sc->dev, "Expect parent #size-cells = [1||2]\n");
+ return (ENXIO);
+ }
+
+ /* Grab the content of reg properties */
+ nreg = OF_getproplen(node, "reg");
+ reg = malloc(nreg, M_DEVBUF, M_WAITOK);
+ OF_getencprop(node, "reg", reg, nreg);
+
+ /* Make sure address & size are 0 */
+ for (idx = 0; idx < REG_MAX; idx++) {
+ sc->reg[idx].address = 0;
+ sc->reg[idx].size = 0;
+ }
+
+ /* Loop through reg-names and figure out which reg-name corresponds to
+ * index populate the values into the reg array.
+ */
+ for (idx = 0, reg_i = 0; idx < REG_MAX && reg_i < nreg; idx++) {
+ err = ofw_bus_find_string_index(node, "reg-names",
+ reg_names[idx], &prop_idx);
+ if (err != 0)
+ continue;
+
+ for (k = 0; k < parent_address_cells; k++) {
+ sc->reg[prop_idx].address <<= 32;
+ sc->reg[prop_idx].address |= reg[reg_i++];
+ }
+
+ for (k = 0; k < parent_size_cells; k++) {
+ sc->reg[prop_idx].size <<= 32;
+ sc->reg[prop_idx].size |= reg[reg_i++];
+ }
+
+ if (sc->sc.nranges == 0)
+ sc->offset_reg[prop_idx] = sc->reg[prop_idx].address;
+ else
+ sc->offset_reg[prop_idx] = sc->reg[prop_idx].address -
+ sc->sc.ranges[REG_REV].host;
+
+ DPRINTF(sc->dev, "reg[%s] adress %#jx size %#jx\n",
+ reg_names[idx],
+ sc->reg[prop_idx].address,
+ sc->reg[prop_idx].size);
+ }
+ free(reg, M_DEVBUF);
+ return (0);
+}
+
+static void
+parse_idle(struct ti_sysc_softc *sc, const char *name, uint32_t *idle) {
+ phandle_t node;
+ cell_t value[SYSC_IDLE_MAX];
+ int len, no, i;
+
+ node = ofw_bus_get_node(sc->dev);
+
+ if (!OF_hasprop(node, name)) {
+ return;
+ }
+
+ len = OF_getproplen(node, name);
+ no = len / sizeof(cell_t);
+ if (no >= SYSC_IDLE_MAX) {
+ DPRINTF(sc->dev, "Limit %s\n", name);
+ no = SYSC_IDLE_MAX-1;
+ len = no * sizeof(cell_t);
+ }
+
+ OF_getencprop(node, name, value, len);
+ for (i = 0; i < no; i++) {
+ idle[i] = value[i];
+#if DEBUG_SYSC
+ DPRINTF(sc->dev, "%s[%d] = %d ",
+ name, i, value[i]);
+ switch(value[i]) {
+ case SYSC_IDLE_FORCE:
+ DPRINTF(sc->dev, "SYSC_IDLE_FORCE\n");
+ break;
+ case SYSC_IDLE_NO:
+ DPRINTF(sc->dev, "SYSC_IDLE_NO\n");
+ break;
+ case SYSC_IDLE_SMART:
+ DPRINTF(sc->dev, "SYSC_IDLE_SMART\n");
+ break;
+ case SYSC_IDLE_SMART_WKUP:
+ DPRINTF(sc->dev, "SYSC_IDLE_SMART_WKUP\n");
+ break;
+ }
+#endif
+ }
+ for ( ; i < SYSC_IDLE_MAX; i++)
+ idle[i] = -1;
+}
+
+static int
+ti_sysc_attach_clocks(struct ti_sysc_softc *sc) {
+ clk_t *clk;
+ struct clk_list *clkp;
+ int index, err;
+ phandle_t cnode;
+
+ clk = malloc(sc->num_clocks*sizeof(clk_t), M_DEVBUF, M_WAITOK | M_ZERO);
+
+ cnode = ofw_bus_get_node(sc->dev);
+
+ /* Check if all clocks can be found */
+ for (index = 0; index < sc->num_clocks; index++) {
+ err = clk_get_by_ofw_index(sc->dev, 0, index, &clk[index]);
+
+ if (err != 0) {
+ free(clk, M_DEVBUF);
+ return (1);
+ }
+ }
+
+ /* All clocks are found, add to list */
+ for (index = 0; index < sc->num_clocks; index++) {
+ clkp = malloc(sizeof(*clkp), M_DEVBUF, M_WAITOK | M_ZERO);
+ clkp->clk = clk[index];
+ TAILQ_INSERT_TAIL(&sc->clk_list, clkp, next);
+ }
+
+ /* Release the clk array */
+ free(clk, M_DEVBUF);
+ return (0);
+}
+
+static int
+ti_sysc_simplebus_attach_child(device_t dev) {
+ device_t cdev;
+ phandle_t node, child;
+ struct ti_sysc_softc *sc = device_get_softc(dev);
+
+ node = ofw_bus_get_node(sc->dev);
+
+ for (child = OF_child(node); child > 0; child = OF_peer(child)) {
+ cdev = simplebus_add_device(sc->dev, child, 0, NULL, -1, NULL);
+ if (cdev != NULL)
+ device_probe_and_attach(cdev);
+ }
+ return (0);
+}
+
+/* Device interface */
+static int
ti_sysc_probe(device_t dev)
{
if (!ofw_bus_status_okay(dev))
@@ -71,8 +455,6 @@ 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);
+ }
+
+ /* 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);
}
- return (bus_generic_attach(dev));
+ 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 <oskar.holmlund@ohdata.se>
+ *
+ * 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 <machine/bus.h>
-#include <arm/ti/ti_prcm.h>
#include <arm/ti/ti_wdt.h>
#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 <machine/bus.h>
-#include <arm/ti/ti_prcm.h>
#include <arm/ti/usb/omap_usb.h>
#include <arm/ti/omap4/pandaboard/pandaboard.h>
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 <machine/bus.h>
-#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/usb/omap_usb.h>
/*
@@ -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 <machine/bus.h>
-#include <arm/ti/ti_prcm.h>
+#include <arm/ti/ti_sysc.h>
#include <arm/ti/usb/omap_usb.h>
/*
@@ -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