freebsd-skq/sys/arm/ti/ti_scm_syscon.c
Michal Meloun 0050ea2415 Move Ti AM335x to dev/extres/clk framework.
Re-implement clocks for these SoC by using now standard extres/clk framework.
This is necessary for future expansion of these. The new  implementation
is (due to the size of the patch) only the initial (minimum) version.
It will be updated/expanded with a subsequent set of particular patches.

This patch is also not tested on OMAP4 based boards (BeagleBone),
so all possible issues should be (and will be) fixed by ASAP once
identified.

Submited by:		Oskar Holmlund (oskar.holmlund@ohdata.se)
Differential Revision:  https://reviews.freebsd.org/D25118
2020-07-30 14:45:05 +00:00

295 lines
7.6 KiB
C

/*-
* 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);