mirror of
https://github.com/AsahiLinux/u-boot
synced 2024-11-24 21:54:01 +00:00
bus: ti: add minimal sysc interconnect target driver
We can handle the sysc interconnect target module in a generic way for many TI SoCs. Initially let's just enable domain clocks before the children are probed. The code is loosely based on the drivers/bus/ti-sysc.c of the Linux kernel version 5.9-rc7. For DT binding details see: - Documentation/devicetree/bindings/bus/ti-sysc.txt Signed-off-by: Dario Binacchi <dariobin@libero.it>
This commit is contained in:
parent
2f59d8f2e0
commit
92cc4e1c21
5 changed files with 176 additions and 0 deletions
|
@ -799,6 +799,7 @@ config ARCH_OMAP2PLUS
|
|||
select SPL_BOARD_INIT if SPL
|
||||
select SPL_STACK_R if SPL
|
||||
select SUPPORT_SPL
|
||||
imply TI_SYSC if DM && OF_CONTROL
|
||||
imply FIT
|
||||
|
||||
config ARCH_MESON
|
||||
|
|
|
@ -4,6 +4,7 @@ CONFIG_ARCH_OMAP2PLUS=y
|
|||
CONFIG_SYS_TEXT_BASE=0x80008000
|
||||
CONFIG_NR_DRAM_BANKS=2
|
||||
CONFIG_TARGET_NOKIA_RX51=y
|
||||
# CONFIG_TI_SYSC is not set
|
||||
# CONFIG_FIT is not set
|
||||
CONFIG_BOOTDELAY=30
|
||||
CONFIG_AUTOBOOT_KEYED=y
|
||||
|
|
|
@ -5,6 +5,13 @@
|
|||
|
||||
menu "Bus devices"
|
||||
|
||||
config TI_SYSC
|
||||
bool "TI sysc interconnect target module driver"
|
||||
depends on ARCH_OMAP2PLUS
|
||||
help
|
||||
Generic driver for Texas Instruments interconnect target module
|
||||
found on many TI SoCs.
|
||||
|
||||
config UNIPHIER_SYSTEM_BUS
|
||||
bool "UniPhier System Bus driver"
|
||||
depends on ARCH_UNIPHIER
|
||||
|
|
|
@ -3,4 +3,5 @@
|
|||
# Makefile for the bus drivers.
|
||||
#
|
||||
|
||||
obj-$(CONFIG_TI_SYSC) += ti-sysc.o
|
||||
obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
|
||||
|
|
166
drivers/bus/ti-sysc.c
Normal file
166
drivers/bus/ti-sysc.c
Normal file
|
@ -0,0 +1,166 @@
|
|||
// SPDX-License-Identifier: GPL-2.0+
|
||||
/*
|
||||
* Texas Instruments sysc interconnect target driver
|
||||
*
|
||||
* Copyright (C) 2020 Dario Binacchi <dariobin@libero.it>
|
||||
*/
|
||||
|
||||
#include <common.h>
|
||||
#include <clk.h>
|
||||
#include <dm.h>
|
||||
#include <dm/device_compat.h>
|
||||
|
||||
enum ti_sysc_clocks {
|
||||
TI_SYSC_FCK,
|
||||
TI_SYSC_ICK,
|
||||
TI_SYSC_MAX_CLOCKS,
|
||||
};
|
||||
|
||||
static const char *const clock_names[] = {"fck", "ick"};
|
||||
|
||||
struct ti_sysc_priv {
|
||||
int clocks_count;
|
||||
struct clk clocks[TI_SYSC_MAX_CLOCKS];
|
||||
};
|
||||
|
||||
static const struct udevice_id ti_sysc_ids[] = {
|
||||
{.compatible = "ti,sysc-omap2"},
|
||||
{.compatible = "ti,sysc-omap4"},
|
||||
{.compatible = "ti,sysc-omap4-simple"},
|
||||
{.compatible = "ti,sysc-omap3430-sr"},
|
||||
{.compatible = "ti,sysc-omap3630-sr"},
|
||||
{.compatible = "ti,sysc-omap4-sr"},
|
||||
{.compatible = "ti,sysc-omap3-sham"},
|
||||
{.compatible = "ti,sysc-omap-aes"},
|
||||
{.compatible = "ti,sysc-mcasp"},
|
||||
{.compatible = "ti,sysc-usb-host-fs"},
|
||||
{}
|
||||
};
|
||||
|
||||
static int ti_sysc_get_one_clock(struct udevice *dev, enum ti_sysc_clocks index)
|
||||
{
|
||||
struct ti_sysc_priv *priv = dev_get_priv(dev);
|
||||
const char *name;
|
||||
int err;
|
||||
|
||||
switch (index) {
|
||||
case TI_SYSC_FCK:
|
||||
break;
|
||||
case TI_SYSC_ICK:
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
name = clock_names[index];
|
||||
|
||||
err = clk_get_by_name(dev, name, &priv->clocks[index]);
|
||||
if (err) {
|
||||
if (err == -ENODATA)
|
||||
return 0;
|
||||
|
||||
dev_err(dev, "failed to get %s clock\n", name);
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_sysc_put_clocks(struct udevice *dev)
|
||||
{
|
||||
struct ti_sysc_priv *priv = dev_get_priv(dev);
|
||||
int err;
|
||||
|
||||
err = clk_release_all(priv->clocks, priv->clocks_count);
|
||||
if (err)
|
||||
dev_err(dev, "failed to release all clocks\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static int ti_sysc_get_clocks(struct udevice *dev)
|
||||
{
|
||||
struct ti_sysc_priv *priv = dev_get_priv(dev);
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < TI_SYSC_MAX_CLOCKS; i++) {
|
||||
err = ti_sysc_get_one_clock(dev, i);
|
||||
if (!err)
|
||||
priv->clocks_count++;
|
||||
else if (err != -ENOENT)
|
||||
return err;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_sysc_child_post_remove(struct udevice *dev)
|
||||
{
|
||||
struct ti_sysc_priv *priv = dev_get_priv(dev->parent);
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < priv->clocks_count; i++) {
|
||||
err = clk_disable(&priv->clocks[i]);
|
||||
if (err) {
|
||||
dev_err(dev->parent, "failed to disable %s clock\n",
|
||||
clock_names[i]);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_sysc_child_pre_probe(struct udevice *dev)
|
||||
{
|
||||
struct ti_sysc_priv *priv = dev_get_priv(dev->parent);
|
||||
int i, err;
|
||||
|
||||
for (i = 0; i < priv->clocks_count; i++) {
|
||||
err = clk_enable(&priv->clocks[i]);
|
||||
if (err) {
|
||||
dev_err(dev->parent, "failed to enable %s clock\n",
|
||||
clock_names[i]);
|
||||
return err;
|
||||
}
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int ti_sysc_remove(struct udevice *dev)
|
||||
{
|
||||
return ti_sysc_put_clocks(dev);
|
||||
}
|
||||
|
||||
static int ti_sysc_probe(struct udevice *dev)
|
||||
{
|
||||
int err;
|
||||
|
||||
err = ti_sysc_get_clocks(dev);
|
||||
if (err)
|
||||
goto clocks_err;
|
||||
|
||||
return 0;
|
||||
|
||||
clocks_err:
|
||||
ti_sysc_put_clocks(dev);
|
||||
return err;
|
||||
}
|
||||
|
||||
UCLASS_DRIVER(ti_sysc) = {
|
||||
.id = UCLASS_SIMPLE_BUS,
|
||||
.name = "ti_sysc",
|
||||
.post_bind = dm_scan_fdt_dev
|
||||
};
|
||||
|
||||
U_BOOT_DRIVER(ti_sysc) = {
|
||||
.name = "ti_sysc",
|
||||
.id = UCLASS_SIMPLE_BUS,
|
||||
.of_match = ti_sysc_ids,
|
||||
.probe = ti_sysc_probe,
|
||||
.remove = ti_sysc_remove,
|
||||
.child_pre_probe = ti_sysc_child_pre_probe,
|
||||
.child_post_remove = ti_sysc_child_post_remove,
|
||||
.priv_auto = sizeof(struct ti_sysc_priv)
|
||||
};
|
Loading…
Reference in a new issue