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:
Dario Binacchi 2020-12-30 00:06:29 +01:00 committed by Lokesh Vutla
parent 2f59d8f2e0
commit 92cc4e1c21
5 changed files with 176 additions and 0 deletions

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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
View 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)
};