Changeset View
Changeset View
Standalone View
Standalone View
head/sys/arm/ti/ti_prcm.c
/*- | /*- | ||||
* SPDX-License-Identifier: BSD-4-Clause | * SPDX-License-Identifier: BSD-2-Clause-FreeBSD | ||||
* | * | ||||
* Copyright (c) 2010 | * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> | ||||
* Ben Gray <ben.r.gray@gmail.com>. | |||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Copyright (c) 2020 Oskar Holmlund <oskar.holmlund@ohdata.se> | |||||
* | |||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
* 1. Redistributions of source code must retain the above copyright | * 1. Redistributions of source code must retain the above copyright | ||||
* notice, this list of conditions and the following disclaimer. | * notice, this list of conditions and the following disclaimer. | ||||
* 2. Redistributions in binary form must reproduce the above copyright | * 2. Redistributions in binary form must reproduce the above copyright | ||||
* notice, this list of conditions and the following disclaimer in the | * notice, this list of conditions and the following disclaimer in the | ||||
* documentation and/or other materials provided with the distribution. | * 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 | * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES | ||||
* OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. | ||||
* IN NO EVENT SHALL BEN GRAY BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, | * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, | ||||
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, | * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, | ||||
* PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; | * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; | ||||
* OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, | * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED | ||||
* WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR | * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, | ||||
* OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF | * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY | ||||
* ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. | * 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 | * $FreeBSD$ | ||||
* the OMAP3 chip. It allows you to turn on and off things like the functional | |||||
* and interface clocks to the various on-chip modules. | |||||
* | |||||
*/ | */ | ||||
/* Based on sys/arm/ti/am335x/am335x_prcm.c */ | |||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <sys/param.h> | #include <sys/param.h> | ||||
#include <sys/systm.h> | #include <sys/systm.h> | ||||
#include <sys/bus.h> | |||||
#include <sys/kernel.h> | #include <sys/kernel.h> | ||||
#include <sys/module.h> | #include <sys/module.h> | ||||
#include <sys/bus.h> | #include <sys/malloc.h> | ||||
#include <sys/resource.h> | |||||
#include <sys/rman.h> | #include <sys/rman.h> | ||||
#include <sys/lock.h> | #include <sys/timeet.h> | ||||
#include <sys/mutex.h> | #include <sys/timetc.h> | ||||
#include <sys/watchdog.h> | |||||
#include <machine/bus.h> | #include <machine/bus.h> | ||||
#include <machine/resource.h> | #include <machine/cpu.h> | ||||
#include <machine/intr.h> | #include <machine/intr.h> | ||||
#include <arm/ti/ti_cpuid.h> | #include <arm/ti/ti_cpuid.h> | ||||
#include <arm/ti/ti_prcm.h> | #include <arm/ti/ti_prcm.h> | ||||
#include <arm/ti/tivar.h> | |||||
/** | #include <dev/fdt/simplebus.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/ofw/openfirm.h> | ||||
* ti_prcm_clk_dev - returns a pointer to the clock device with given id | #include <dev/ofw/ofw_bus.h> | ||||
* @clk: the ID of the clock device to get | #include <dev/ofw/ofw_bus_subr.h> | ||||
* | |||||
* Simply iterates through the clk_devmap global array and returns a pointer | #include "clkdev_if.h" | ||||
* to the clock device if found. | |||||
* | #if 0 | ||||
* LOCKING: | #define DPRINTF(dev, msg...) device_printf(dev, msg) | ||||
* None | #else | ||||
* | #define DPRINTF(dev, msg...) | ||||
* RETURNS: | #endif | ||||
* The pointer to the clock device on success, on failure NULL is returned. | |||||
*/ | struct ti_prcm_softc { | ||||
static struct ti_clock_dev * | struct simplebus_softc sc_simplebus; | ||||
ti_prcm_clk_dev(clk_ident_t clk) | 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; | if (!ofw_bus_status_okay(dev)) | ||||
return (ENXIO); | |||||
/* Find the clock within the devmap - it's a bit inefficent having a for | if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) { | ||||
* loop for this, but this function should only called when a driver is | return (ENXIO); | ||||
* being activated so IMHO not a big issue. | } | ||||
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()) { | switch(ti_chip()) { | ||||
#ifdef SOC_OMAP4 | #ifdef SOC_OMAP4 | ||||
case CHIP_OMAP_4: | case CHIP_OMAP_4: | ||||
clk_dev = &(ti_omap4_clk_devmap[0]); | ti_cpu_reset = omap4_prcm_reset; | ||||
break; | break; | ||||
#endif | #endif | ||||
#ifdef SOC_TI_AM335X | #ifdef SOC_TI_AM335X | ||||
case CHIP_AM335X: | case CHIP_AM335X: | ||||
clk_dev = &(ti_am335x_clk_devmap[0]); | ti_cpu_reset = am335x_prcm_reset; | ||||
break; | break; | ||||
#endif | #endif | ||||
} | } | ||||
if (clk_dev == NULL) | |||||
panic("No clock devmap found"); | bus_generic_probe(sc->dev); | ||||
while (clk_dev->id != INVALID_CLK_IDENT) { | for (child = OF_child(node); child != 0; child = OF_peer(child)) { | ||||
if (clk_dev->id == clk) { | simplebus_add_device(dev, child, 0, NULL, -1, NULL); | ||||
return (clk_dev); | |||||
} | } | ||||
clk_dev++; | |||||
} | |||||
/* Sanity check we managed to find the clock */ | return (bus_generic_attach(sc->dev)); | ||||
printf("ti_prcm: Failed to find clock device (%d)\n", clk); | |||||
return (NULL); | |||||
} | } | ||||
/** | |||||
* ti_prcm_clk_valid - enables a clock for a particular module | |||||
* @clk: identifier for the module to enable, see ti_prcm.h for a list | |||||
* of possible modules. | |||||
* Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. | |||||
* | |||||
* This function can enable either a functional or interface clock. | |||||
* | |||||
* The real work done to enable the clock is really done in the callback | |||||
* function associated with the clock, this function is simply a wrapper | |||||
* around that. | |||||
* | |||||
* LOCKING: | |||||
* Internally locks the driver context. | |||||
* | |||||
* RETURNS: | |||||
* Returns 0 on success or positive error code on failure. | |||||
*/ | |||||
int | 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) | sc = device_get_softc(dev); | ||||
ret = EINVAL; | DPRINTF(sc->dev, "offset=%lx write %x\n", addr, val); | ||||
bus_space_write_4(sc->bst, sc->bsh, addr, val); | |||||
return (ret); | 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 | int | ||||
ti_prcm_clk_enable(clk_ident_t clk) | ti_prcm_read_4(device_t dev, bus_addr_t addr, uint32_t *val) | ||||
{ | { | ||||
struct ti_clock_dev *clk_dev; | struct ti_prcm_softc *sc; | ||||
int ret; | |||||
/* Find the clock within the devmap - it's a bit inefficent having a for | sc = device_get_softc(dev); | ||||
* 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 */ | *val = bus_space_read_4(sc->bst, sc->bsh, addr); | ||||
if (clk_dev == NULL) | DPRINTF(sc->dev, "offset=%lx Read %x\n", addr, *val); | ||||
return (EINVAL); | return (0); | ||||
/* Activate the clock */ | |||||
if (clk_dev->clk_activate) | |||||
ret = clk_dev->clk_activate(clk_dev); | |||||
else | |||||
ret = EINVAL; | |||||
return (ret); | |||||
} | } | ||||
/** | |||||
* ti_prcm_clk_disable - disables a clock for a particular module | |||||
* @clk: identifier for the module to enable, see ti_prcm.h for a list | |||||
* of possible modules. | |||||
* Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. | |||||
* | |||||
* This function can enable either a functional or interface clock. | |||||
* | |||||
* The real work done to enable the clock is really done in the callback | |||||
* function associated with the clock, this function is simply a wrapper | |||||
* around that. | |||||
* | |||||
* LOCKING: | |||||
* Internally locks the driver context. | |||||
* | |||||
* RETURNS: | |||||
* Returns 0 on success or positive error code on failure. | |||||
*/ | |||||
int | int | ||||
ti_prcm_clk_disable(clk_ident_t clk) | ti_prcm_modify_4(device_t dev, bus_addr_t addr, uint32_t clr, uint32_t set) | ||||
{ | { | ||||
struct ti_clock_dev *clk_dev; | struct ti_prcm_softc *sc; | ||||
int ret; | uint32_t reg; | ||||
/* Find the clock within the devmap - it's a bit inefficent having a for | sc = device_get_softc(dev); | ||||
* 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 */ | reg = bus_space_read_4(sc->bst, sc->bsh, addr); | ||||
if (clk_dev == NULL) | reg &= ~clr; | ||||
return (EINVAL); | reg |= set; | ||||
bus_space_write_4(sc->bst, sc->bsh, addr, reg); | |||||
DPRINTF(sc->dev, "offset=%lx reg: %x (clr %x set %x)\n", addr, reg, clr, set); | |||||
/* Activate the clock */ | return (0); | ||||
if (clk_dev->clk_deactivate) | } | ||||
ret = clk_dev->clk_deactivate(clk_dev); | |||||
else | |||||
ret = EINVAL; | |||||
return (ret); | void | ||||
ti_prcm_device_lock(device_t dev) | |||||
{ | |||||
struct ti_prcm_softc *sc; | |||||
sc = device_get_softc(dev); | |||||
mtx_lock(&sc->mtx); | |||||
} | } | ||||
/** | void | ||||
* ti_prcm_clk_set_source - sets the source | ti_prcm_device_unlock(device_t dev) | ||||
* @clk: identifier for the module to enable, see ti_prcm.h for a list | |||||
* of possible modules. | |||||
* Example: OMAP3_MODULE_MMC1_ICLK or OMAP3_MODULE_GPTIMER10_FCLK. | |||||
* | |||||
* This function can enable either a functional or interface clock. | |||||
* | |||||
* The real work done to enable the clock is really done in the callback | |||||
* function associated with the clock, this function is simply a wrapper | |||||
* around that. | |||||
* | |||||
* LOCKING: | |||||
* Internally locks the driver context. | |||||
* | |||||
* RETURNS: | |||||
* Returns 0 on success or positive error code on failure. | |||||
*/ | |||||
int | |||||
ti_prcm_clk_set_source(clk_ident_t clk, clk_src_t clksrc) | |||||
{ | { | ||||
struct ti_clock_dev *clk_dev; | struct ti_prcm_softc *sc; | ||||
int ret; | |||||
/* Find the clock within the devmap - it's a bit inefficent having a for | sc = device_get_softc(dev); | ||||
* loop for this, but this function should only called when a driver is | mtx_unlock(&sc->mtx); | ||||
* being activated so IMHO not a big issue. | } | ||||
*/ | |||||
clk_dev = ti_prcm_clk_dev(clk); | |||||
/* Sanity check we managed to find the clock */ | static device_method_t ti_prcm_methods[] = { | ||||
if (clk_dev == NULL) | DEVMETHOD(device_probe, ti_prcm_probe), | ||||
return (EINVAL); | DEVMETHOD(device_attach, ti_prcm_attach), | ||||
/* Activate the clock */ | /* clkdev interface */ | ||||
if (clk_dev->clk_set_source) | DEVMETHOD(clkdev_write_4, ti_prcm_write_4), | ||||
ret = clk_dev->clk_set_source(clk_dev, clksrc); | DEVMETHOD(clkdev_read_4, ti_prcm_read_4), | ||||
else | DEVMETHOD(clkdev_modify_4, ti_prcm_modify_4), | ||||
ret = EINVAL; | 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); | |||||
/** | static devclass_t ti_prcm_devclass; | ||||
* ti_prcm_clk_get_source_freq - gets the source clock frequency | |||||
* @clk: identifier for the module to enable, see ti_prcm.h for a list | |||||
* of possible modules. | |||||
* @freq: pointer to an integer that upon return will contain the src freq | |||||
* | |||||
* This function returns the frequency of the source clock. | |||||
* | |||||
* The real work done to enable the clock is really done in the callback | |||||
* function associated with the clock, this function is simply a wrapper | |||||
* around that. | |||||
* | |||||
* LOCKING: | |||||
* Internally locks the driver context. | |||||
* | |||||
* RETURNS: | |||||
* Returns 0 on success or positive error code on failure. | |||||
*/ | |||||
int | |||||
ti_prcm_clk_get_source_freq(clk_ident_t clk, unsigned int *freq) | |||||
{ | |||||
struct ti_clock_dev *clk_dev; | |||||
int ret; | |||||
/* Find the clock within the devmap - it's a bit inefficent having a for | EARLY_DRIVER_MODULE(ti_prcm, ofwbus, ti_prcm_driver, | ||||
* loop for this, but this function should only called when a driver is | ti_prcm_devclass, 0, 0, BUS_PASS_BUS); | ||||
* being activated so IMHO not a big issue. | EARLY_DRIVER_MODULE(ti_prcm, simplebus, ti_prcm_driver, | ||||
*/ | ti_prcm_devclass, 0, 0, BUS_PASS_BUS + BUS_PASS_ORDER_MIDDLE); | ||||
clk_dev = ti_prcm_clk_dev(clk); | 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 */ | /* From sys/arm/ti/am335x/am335x_prcm.c | ||||
if (clk_dev->clk_get_source_freq) | * Copyright (c) 2012 Damjan Marion <dmarion@Freebsd.org> | ||||
ret = clk_dev->clk_get_source_freq(clk_dev, freq); | */ | ||||
else | #define PRM_DEVICE_OFFSET 0xF00 | ||||
ret = EINVAL; | #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)); | |||||
} | } | ||||
/** | /* FIXME: Is this correct - or should the license part be ontop? */ | ||||
* 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 | /* From sys/arm/ti/omap4/omap4_prcm_clks.c */ | ||||
* of possible modules. | /*- | ||||
* @freq: requested freq | * SPDX-License-Identifier: BSD-3-Clause | ||||
* | * | ||||
* LOCKING: | * Copyright (c) 2011 | ||||
* Internally locks the driver context. | * Ben Gray <ben.r.gray@gmail.com>. | ||||
* All rights reserved. | |||||
* | * | ||||
* RETURNS: | * Redistribution and use in source and binary forms, with or without | ||||
* Returns 0 on success or positive error code on failure. | * 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 | #define PRM_RSTCTRL 0x1b00 | ||||
ti_prcm_clk_set_source_freq(clk_ident_t clk, unsigned int freq) | #define PRM_RSTCTRL_RESET 0x2 | ||||
static void | |||||
omap4_prcm_reset(void) | |||||
{ | { | ||||
struct ti_clock_dev *clk_dev; | uint32_t reg; | ||||
int ret; | |||||
clk_dev = ti_prcm_clk_dev(clk); | ti_prcm_read_4(ti_prcm_sc->dev, PRM_RSTCTRL, ®); | ||||
reg = reg | PRM_RSTCTRL_RESET; | |||||
/* Sanity check we managed to find the clock */ | ti_prcm_write_4(ti_prcm_sc->dev, PRM_RSTCTRL, reg); | ||||
if (clk_dev == NULL) | ti_prcm_read_4(ti_prcm_sc->dev, PRM_RSTCTRL, ®); | ||||
return (EINVAL); | |||||
/* Get the source frequency of the clock */ | |||||
if (clk_dev->clk_set_source_freq) | |||||
ret = clk_dev->clk_set_source_freq(clk_dev, freq); | |||||
else | |||||
ret = EINVAL; | |||||
return (ret); | |||||
} | } |