Commit aa78dd16 authored by Olof Johansson's avatar Olof Johansson

Merge tag 'drivers_soc_for_5.10' of...

Merge tag 'drivers_soc_for_5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone into arm/drivers

ARM: soc: TI driver updates for v5.10

Consist of:
 - Add Ring accelerator support for AM65x
 - Add TI PRUSS platform driver and enable it on available platforms
 - Extend PRUSS driver for CORECLK_MUX/IEPCLK_MUX support
 - UDMA rx ring pair fix
 - Add socinfo entry for J7200

* tag 'drivers_soc_for_5.10' of git://git.kernel.org/pub/scm/linux/kernel/git/ssantosh/linux-keystone:
  Add missing '#' to fix schema errors:
  soc: ti: Convert to DEFINE_SHOW_ATTRIBUTE
  dmaengine: ti: k3-udma-glue: Fix parameters for rx ring pair request
  soc: ti: k3-socinfo: Add entry for J7200
  soc: ti: pruss: support CORECLK_MUX and IEPCLK_MUX
  dt-bindings: soc: ti: Update TI PRUSS bindings regarding clock-muxes
  firmware: ti_sci: allow frequency change for disabled clocks by default
  soc: ti: ti_sci_pm_domains: switch to use multiple genpds instead of one
  soc: ti: pruss: Enable support for ICSSG subsystems on K3 J721E SoCs
  soc: ti: pruss: Enable support for ICSSG subsystems on K3 AM65x SoCs
  soc: ti: pruss: Add support for PRU-ICSS subsystems on 66AK2G SoC
  soc: ti: pruss: Add support for PRU-ICSS subsystems on AM57xx SoCs
  soc: ti: pruss: Add support for PRU-ICSSs on AM437x SoCs
  soc: ti: pruss: Add a platform driver for PRUSS in TI SoCs
  dt-bindings: soc: ti: Add TI PRUSS bindings
  bindings: soc: ti: soc: ringacc: remove ti,dma-ring-reset-quirk
  soc: ti: k3: ringacc: add am65x sr2.0 support

Link: https://lore.kernel.org/r/1600656828-29267-1-git-send-email-santosh.shilimkar@oracle.comSigned-off-by: default avatarOlof Johansson <olof@lixom.net>
parents 63e15ef1 dcca7a97
......@@ -62,11 +62,6 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32
description: TI-SCI device id of the ring accelerator
ti,dma-ring-reset-quirk:
$ref: /schemas/types.yaml#definitions/flag
description: |
enable ringacc/udma ring state interoperability issue software w/a
required:
- compatible
- reg
......@@ -94,7 +89,6 @@ examples:
reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target";
ti,num-rings = <818>;
ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */
ti,dma-ring-reset-quirk;
ti,sci = <&dmsc>;
ti,sci-dev-id = <187>;
msi-parent = <&inta_main_udmass>;
......
This diff is collapsed.
......@@ -579,8 +579,8 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
/* request and cfg rings */
ret = k3_ringacc_request_rings_pair(rx_chn->common.ringacc,
flow_cfg->ring_rxq_id,
flow_cfg->ring_rxfdq0_id,
flow_cfg->ring_rxq_id,
&flow->ringrxfdq,
&flow->ringrx);
if (ret) {
......
......@@ -1124,7 +1124,8 @@ static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id,
static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
u32 dev_id, u32 clk_id)
{
return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
return ti_sci_set_clock_state(handle, dev_id, clk_id,
MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE,
MSG_CLOCK_SW_STATE_UNREQ);
}
......@@ -1143,7 +1144,8 @@ static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
u32 dev_id, u32 clk_id)
{
return ti_sci_set_clock_state(handle, dev_id, clk_id, 0,
return ti_sci_set_clock_state(handle, dev_id, clk_id,
MSG_FLAG_CLOCK_ALLOW_FREQ_CHANGE,
MSG_CLOCK_SW_STATE_AUTO);
}
......
......@@ -101,6 +101,17 @@ config TI_K3_SOCINFO
platforms to provide information about the SoC family and
variant to user space.
config TI_PRUSS
tristate "TI PRU-ICSS Subsystem Platform drivers"
depends on SOC_AM33XX || SOC_AM43XX || SOC_DRA7XX || ARCH_KEYSTONE || ARCH_K3
select MFD_SYSCON
help
TI PRU-ICSS Subsystem platform specific support.
Say Y or M here to support the Programmable Realtime Unit (PRU)
processors on various TI SoCs. It's safe to say N here if you're
not interested in the PRU or if you are unsure.
endif # SOC_TI
config TI_SCI_INTA_MSI_DOMAIN
......
......@@ -12,3 +12,4 @@ obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o
obj-$(CONFIG_TI_SCI_INTA_MSI_DOMAIN) += ti_sci_inta_msi.o
obj-$(CONFIG_TI_K3_RINGACC) += k3-ringacc.o
obj-$(CONFIG_TI_K3_SOCINFO) += k3-socinfo.o
obj-$(CONFIG_TI_PRUSS) += pruss.o
......@@ -10,6 +10,7 @@
#include <linux/init.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/sys_soc.h>
#include <linux/soc/ti/k3-ringacc.h>
#include <linux/soc/ti/ti_sci_protocol.h>
#include <linux/soc/ti/ti_sci_inta_msi.h>
......@@ -208,6 +209,15 @@ struct k3_ringacc {
const struct k3_ringacc_ops *ops;
};
/**
* struct k3_ringacc - Rings accelerator SoC data
*
* @dma_ring_reset_quirk: DMA reset w/a enable
*/
struct k3_ringacc_soc_data {
unsigned dma_ring_reset_quirk:1;
};
static long k3_ringacc_ring_get_fifo_pos(struct k3_ring *ring)
{
return K3_RINGACC_FIFO_WINDOW_SIZE_BYTES -
......@@ -1051,9 +1061,6 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
return ret;
}
ringacc->dma_ring_reset_quirk =
of_property_read_bool(node, "ti,dma-ring-reset-quirk");
ringacc->tisci = ti_sci_get_by_phandle(node, "ti,sci");
if (IS_ERR(ringacc->tisci)) {
ret = PTR_ERR(ringacc->tisci);
......@@ -1084,9 +1091,22 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
ringacc->rm_gp_range);
}
static const struct k3_ringacc_soc_data k3_ringacc_soc_data_sr1 = {
.dma_ring_reset_quirk = 1,
};
static const struct soc_device_attribute k3_ringacc_socinfo[] = {
{ .family = "AM65X",
.revision = "SR1.0",
.data = &k3_ringacc_soc_data_sr1
},
{/* sentinel */}
};
static int k3_ringacc_init(struct platform_device *pdev,
struct k3_ringacc *ringacc)
{
const struct soc_device_attribute *soc;
void __iomem *base_fifo, *base_rt;
struct device *dev = &pdev->dev;
struct resource *res;
......@@ -1103,6 +1123,13 @@ static int k3_ringacc_init(struct platform_device *pdev,
if (ret)
return ret;
soc = soc_device_match(k3_ringacc_socinfo);
if (soc && soc->data) {
const struct k3_ringacc_soc_data *soc_data = soc->data;
ringacc->dma_ring_reset_quirk = soc_data->dma_ring_reset_quirk;
}
res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt");
base_rt = devm_ioremap_resource(dev, res);
if (IS_ERR(base_rt))
......
......@@ -39,6 +39,7 @@ static const struct k3_soc_id {
} k3_soc_ids[] = {
{ 0xBB5A, "AM65X" },
{ 0xBB64, "J721E" },
{ 0xBB6D, "J7200" },
};
static int
......
......@@ -355,7 +355,7 @@ static void dma_debug_show_devices(struct seq_file *s,
}
}
static int dma_debug_show(struct seq_file *s, void *v)
static int knav_dma_debug_show(struct seq_file *s, void *v)
{
struct knav_dma_device *dma;
......@@ -370,17 +370,7 @@ static int dma_debug_show(struct seq_file *s, void *v)
return 0;
}
static int knav_dma_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, dma_debug_show, NULL);
}
static const struct file_operations knav_dma_debug_ops = {
.open = knav_dma_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(knav_dma_debug);
static int of_channel_match_helper(struct device_node *np, const char *name,
const char **dma_instance)
......@@ -778,7 +768,7 @@ static int knav_dma_probe(struct platform_device *pdev)
}
debugfs_create_file("knav_dma", S_IFREG | S_IRUGO, NULL, NULL,
&knav_dma_debug_ops);
&knav_dma_debug_fops);
device_ready = true;
return ret;
......
......@@ -478,17 +478,7 @@ static int knav_queue_debug_show(struct seq_file *s, void *v)
return 0;
}
static int knav_queue_debug_open(struct inode *inode, struct file *file)
{
return single_open(file, knav_queue_debug_show, NULL);
}
static const struct file_operations knav_queue_debug_ops = {
.open = knav_queue_debug_open,
.read = seq_read,
.llseek = seq_lseek,
.release = single_release,
};
DEFINE_SHOW_ATTRIBUTE(knav_queue_debug);
static inline int knav_queue_pdsp_wait(u32 * __iomem addr, unsigned timeout,
u32 flags)
......@@ -1878,7 +1868,7 @@ static int knav_queue_probe(struct platform_device *pdev)
}
debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL,
&knav_queue_debug_ops);
&knav_queue_debug_fops);
device_ready = true;
return 0;
......
// SPDX-License-Identifier: GPL-2.0-only
/*
* PRU-ICSS platform driver for various TI SoCs
*
* Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/
* Author(s):
* Suman Anna <s-anna@ti.com>
* Andrew F. Davis <afd@ti.com>
*/
#include <linux/clk-provider.h>
#include <linux/dma-mapping.h>
#include <linux/io.h>
#include <linux/mfd/syscon.h>
#include <linux/module.h>
#include <linux/of_address.h>
#include <linux/of_device.h>
#include <linux/pm_runtime.h>
#include <linux/pruss_driver.h>
#include <linux/regmap.h>
#include <linux/slab.h>
/**
* struct pruss_private_data - PRUSS driver private data
* @has_no_sharedram: flag to indicate the absence of PRUSS Shared Data RAM
* @has_core_mux_clock: flag to indicate the presence of PRUSS core clock
*/
struct pruss_private_data {
bool has_no_sharedram;
bool has_core_mux_clock;
};
static void pruss_of_free_clk_provider(void *data)
{
struct device_node *clk_mux_np = data;
of_clk_del_provider(clk_mux_np);
of_node_put(clk_mux_np);
}
static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
char *mux_name, struct device_node *clks_np)
{
struct device_node *clk_mux_np;
struct device *dev = pruss->dev;
char *clk_mux_name;
unsigned int num_parents;
const char **parent_names;
void __iomem *reg;
u32 reg_offset;
int ret;
clk_mux_np = of_get_child_by_name(clks_np, mux_name);
if (!clk_mux_np) {
dev_err(dev, "%pOF is missing its '%s' node\n", clks_np,
mux_name);
return -ENODEV;
}
num_parents = of_clk_get_parent_count(clk_mux_np);
if (num_parents < 1) {
dev_err(dev, "mux-clock %pOF must have parents\n", clk_mux_np);
ret = -EINVAL;
goto put_clk_mux_np;
}
parent_names = devm_kcalloc(dev, sizeof(*parent_names), num_parents,
GFP_KERNEL);
if (!parent_names) {
ret = -ENOMEM;
goto put_clk_mux_np;
}
of_clk_parent_fill(clk_mux_np, parent_names, num_parents);
clk_mux_name = devm_kasprintf(dev, GFP_KERNEL, "%s.%pOFn",
dev_name(dev), clk_mux_np);
if (!clk_mux_name) {
ret = -ENOMEM;
goto put_clk_mux_np;
}
ret = of_property_read_u32(clk_mux_np, "reg", &reg_offset);
if (ret)
goto put_clk_mux_np;
reg = pruss->cfg_base + reg_offset;
clk_mux = clk_register_mux(NULL, clk_mux_name, parent_names,
num_parents, 0, reg, 0, 1, 0, NULL);
if (IS_ERR(clk_mux)) {
ret = PTR_ERR(clk_mux);
goto put_clk_mux_np;
}
ret = devm_add_action_or_reset(dev, (void(*)(void *))clk_unregister_mux,
clk_mux);
if (ret) {
dev_err(dev, "failed to add clkmux unregister action %d", ret);
goto put_clk_mux_np;
}
ret = of_clk_add_provider(clk_mux_np, of_clk_src_simple_get, clk_mux);
if (ret)
goto put_clk_mux_np;
ret = devm_add_action_or_reset(dev, pruss_of_free_clk_provider,
clk_mux_np);
if (ret) {
dev_err(dev, "failed to add clkmux free action %d", ret);
goto put_clk_mux_np;
}
return 0;
put_clk_mux_np:
of_node_put(clk_mux_np);
return ret;
}
static int pruss_clk_init(struct pruss *pruss, struct device_node *cfg_node)
{
const struct pruss_private_data *data;
struct device_node *clks_np;
struct device *dev = pruss->dev;
int ret = 0;
data = of_device_get_match_data(dev);
if (IS_ERR(data))
return -ENODEV;
clks_np = of_get_child_by_name(cfg_node, "clocks");
if (!clks_np) {
dev_err(dev, "%pOF is missing its 'clocks' node\n", clks_np);
return -ENODEV;
}
if (data && data->has_core_mux_clock) {
ret = pruss_clk_mux_setup(pruss, pruss->core_clk_mux,
"coreclk-mux", clks_np);
if (ret) {
dev_err(dev, "failed to setup coreclk-mux\n");
goto put_clks_node;
}
}
ret = pruss_clk_mux_setup(pruss, pruss->iep_clk_mux, "iepclk-mux",
clks_np);
if (ret) {
dev_err(dev, "failed to setup iepclk-mux\n");
goto put_clks_node;
}
put_clks_node:
of_node_put(clks_np);
return ret;
}
static struct regmap_config regmap_conf = {
.reg_bits = 32,
.val_bits = 32,
.reg_stride = 4,
};
static int pruss_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev_of_node(dev);
struct device_node *child;
struct pruss *pruss;
struct resource res;
int ret, i, index;
const struct pruss_private_data *data;
const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
data = of_device_get_match_data(&pdev->dev);
if (IS_ERR(data)) {
dev_err(dev, "missing private data\n");
return -ENODEV;
}
ret = dma_set_coherent_mask(dev, DMA_BIT_MASK(32));
if (ret) {
dev_err(dev, "failed to set the DMA coherent mask");
return ret;
}
pruss = devm_kzalloc(dev, sizeof(*pruss), GFP_KERNEL);
if (!pruss)
return -ENOMEM;
pruss->dev = dev;
child = of_get_child_by_name(np, "memories");
if (!child) {
dev_err(dev, "%pOF is missing its 'memories' node\n", child);
return -ENODEV;
}
for (i = 0; i < PRUSS_MEM_MAX; i++) {
/*
* On AM437x one of two PRUSS units don't contain Shared RAM,
* skip it
*/
if (data && data->has_no_sharedram && i == PRUSS_MEM_SHRD_RAM2)
continue;
index = of_property_match_string(child, "reg-names",
mem_names[i]);
if (index < 0) {
of_node_put(child);
return index;
}
if (of_address_to_resource(child, index, &res)) {
of_node_put(child);
return -EINVAL;
}
pruss->mem_regions[i].va = devm_ioremap(dev, res.start,
resource_size(&res));
if (!pruss->mem_regions[i].va) {
dev_err(dev, "failed to parse and map memory resource %d %s\n",
i, mem_names[i]);
of_node_put(child);
return -ENOMEM;
}
pruss->mem_regions[i].pa = res.start;
pruss->mem_regions[i].size = resource_size(&res);
dev_dbg(dev, "memory %8s: pa %pa size 0x%zx va %pK\n",
mem_names[i], &pruss->mem_regions[i].pa,
pruss->mem_regions[i].size, pruss->mem_regions[i].va);
}
of_node_put(child);
platform_set_drvdata(pdev, pruss);
pm_runtime_enable(dev);
ret = pm_runtime_get_sync(dev);
if (ret < 0) {
dev_err(dev, "couldn't enable module\n");
pm_runtime_put_noidle(dev);
goto rpm_disable;
}
child = of_get_child_by_name(np, "cfg");
if (!child) {
dev_err(dev, "%pOF is missing its 'cfg' node\n", child);
ret = -ENODEV;
goto rpm_put;
}
if (of_address_to_resource(child, 0, &res)) {
ret = -ENOMEM;
goto node_put;
}
pruss->cfg_base = devm_ioremap(dev, res.start, resource_size(&res));
if (!pruss->cfg_base) {
ret = -ENOMEM;
goto node_put;
}
regmap_conf.name = kasprintf(GFP_KERNEL, "%pOFn@%llx", child,
(u64)res.start);
regmap_conf.max_register = resource_size(&res) - 4;
pruss->cfg_regmap = devm_regmap_init_mmio(dev, pruss->cfg_base,
&regmap_conf);
kfree(regmap_conf.name);
if (IS_ERR(pruss->cfg_regmap)) {
dev_err(dev, "regmap_init_mmio failed for cfg, ret = %ld\n",
PTR_ERR(pruss->cfg_regmap));
ret = PTR_ERR(pruss->cfg_regmap);
goto node_put;
}
ret = pruss_clk_init(pruss, child);
if (ret) {
dev_err(dev, "failed to setup coreclk-mux\n");
goto node_put;
}
ret = devm_of_platform_populate(dev);
if (ret) {
dev_err(dev, "failed to register child devices\n");
goto node_put;
}
of_node_put(child);
return 0;
node_put:
of_node_put(child);
rpm_put:
pm_runtime_put_sync(dev);
rpm_disable:
pm_runtime_disable(dev);
return ret;
}
static int pruss_remove(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
devm_of_platform_depopulate(dev);
pm_runtime_put_sync(dev);
pm_runtime_disable(dev);
return 0;
}
/* instance-specific driver private data */
static const struct pruss_private_data am437x_pruss1_data = {
.has_no_sharedram = false,
};
static const struct pruss_private_data am437x_pruss0_data = {
.has_no_sharedram = true,
};
static const struct pruss_private_data am65x_j721e_pruss_data = {
.has_core_mux_clock = true,
};
static const struct of_device_id pruss_of_match[] = {
{ .compatible = "ti,am3356-pruss" },
{ .compatible = "ti,am4376-pruss0", .data = &am437x_pruss0_data, },
{ .compatible = "ti,am4376-pruss1", .data = &am437x_pruss1_data, },
{ .compatible = "ti,am5728-pruss" },
{ .compatible = "ti,k2g-pruss" },
{ .compatible = "ti,am654-icssg", .data = &am65x_j721e_pruss_data, },
{ .compatible = "ti,j721e-icssg", .data = &am65x_j721e_pruss_data, },
{},
};
MODULE_DEVICE_TABLE(of, pruss_of_match);
static struct platform_driver pruss_driver = {
.driver = {
.name = "pruss",
.of_match_table = pruss_of_match,
},
.probe = pruss_probe,
.remove = pruss_remove,
};
module_platform_driver(pruss_driver);
MODULE_AUTHOR("Suman Anna <s-anna@ti.com>");
MODULE_DESCRIPTION("PRU-ICSS Subsystem Driver");
MODULE_LICENSE("GPL v2");
......@@ -9,7 +9,6 @@
#include <linux/err.h>
#include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/pm_domain.h>
......@@ -18,150 +17,95 @@
#include <dt-bindings/soc/ti,sci_pm_domain.h>
/**
* struct ti_sci_genpd_dev_data: holds data needed for every device attached
* to this genpd
* @idx: index of the device that identifies it with the system
* control processor.
* @exclusive: Permissions for exclusive request or shared request of the
* device.
* struct ti_sci_genpd_provider: holds common TI SCI genpd provider data
* @ti_sci: handle to TI SCI protocol driver that provides ops to
* communicate with system control processor.
* @dev: pointer to dev for the driver for devm allocs
* @pd_list: list of all the power domains on the device
* @data: onecell data for genpd core
*/
struct ti_sci_genpd_dev_data {
int idx;
u8 exclusive;
struct ti_sci_genpd_provider {
const struct ti_sci_handle *ti_sci;
struct device *dev;
struct list_head pd_list;
struct genpd_onecell_data data;
};
/**
* struct ti_sci_pm_domain: TI specific data needed for power domain
* @ti_sci: handle to TI SCI protocol driver that provides ops to
* communicate with system control processor.
* @dev: pointer to dev for the driver for devm allocs
* @idx: index of the device that identifies it with the system
* control processor.
* @exclusive: Permissions for exclusive request or shared request of the
* device.
* @pd: generic_pm_domain for use with the genpd framework
* @node: link for the genpd list
* @parent: link to the parent TI SCI genpd provider
*/
struct ti_sci_pm_domain {
const struct ti_sci_handle *ti_sci;
struct device *dev;
int idx;
u8 exclusive;
struct generic_pm_domain pd;
struct list_head node;
struct ti_sci_genpd_provider *parent;
};
#define genpd_to_ti_sci_pd(gpd) container_of(gpd, struct ti_sci_pm_domain, pd)
/**
* ti_sci_dev_id(): get prepopulated ti_sci id from struct dev
* @dev: pointer to device associated with this genpd
*
* Returns device_id stored from ti,sci_id property
*/
static int ti_sci_dev_id(struct device *dev)
{
struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
return sci_dev_data->idx;
}
static u8 is_ti_sci_dev_exclusive(struct device *dev)
{
struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
return sci_dev_data->exclusive;
}
/**
* ti_sci_dev_to_sci_handle(): get pointer to ti_sci_handle
* @dev: pointer to device associated with this genpd
*
* Returns ti_sci_handle to be used to communicate with system
* control processor.
/*
* ti_sci_pd_power_off(): genpd power down hook
* @domain: pointer to the powerdomain to power off
*/
static const struct ti_sci_handle *ti_sci_dev_to_sci_handle(struct device *dev)
static int ti_sci_pd_power_off(struct generic_pm_domain *domain)
{
struct generic_pm_domain *pd = pd_to_genpd(dev->pm_domain);
struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(pd);
struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
return ti_sci_genpd->ti_sci;
return ti_sci->ops.dev_ops.put_device(ti_sci, pd->idx);
}
/**
* ti_sci_dev_start(): genpd device start hook called to turn device on
* @dev: pointer to device associated with this genpd to be powered on
/*
* ti_sci_pd_power_on(): genpd power up hook
* @domain: pointer to the powerdomain to power on
*/
static int ti_sci_dev_start(struct device *dev)
static int ti_sci_pd_power_on(struct generic_pm_domain *domain)
{
const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
int idx = ti_sci_dev_id(dev);
struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
if (is_ti_sci_dev_exclusive(dev))
return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci, idx);
if (pd->exclusive)
return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci,
pd->idx);
else
return ti_sci->ops.dev_ops.get_device(ti_sci, idx);
return ti_sci->ops.dev_ops.get_device(ti_sci, pd->idx);
}
/**
* ti_sci_dev_stop(): genpd device stop hook called to turn device off
* @dev: pointer to device associated with this genpd to be powered off
/*
* ti_sci_pd_xlate(): translation service for TI SCI genpds
* @genpdspec: DT identification data for the genpd
* @data: genpd core data for all the powerdomains on the device
*/
static int ti_sci_dev_stop(struct device *dev)
static struct generic_pm_domain *ti_sci_pd_xlate(
struct of_phandle_args *genpdspec,
void *data)
{
const struct ti_sci_handle *ti_sci = ti_sci_dev_to_sci_handle(dev);
int idx = ti_sci_dev_id(dev);
struct genpd_onecell_data *genpd_data = data;
unsigned int idx = genpdspec->args[0];
return ti_sci->ops.dev_ops.put_device(ti_sci, idx);
}
if (genpdspec->args_count < 2)
return ERR_PTR(-EINVAL);
static int ti_sci_pd_attach_dev(struct generic_pm_domain *domain,
struct device *dev)
{
struct device_node *np = dev->of_node;
struct of_phandle_args pd_args;
struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(domain);
const struct ti_sci_handle *ti_sci = ti_sci_genpd->ti_sci;
struct ti_sci_genpd_dev_data *sci_dev_data;
struct generic_pm_domain_data *genpd_data;
int idx, ret = 0;
ret = of_parse_phandle_with_args(np, "power-domains",
"#power-domain-cells", 0, &pd_args);
if (ret < 0)
return ret;
if (pd_args.args_count != 1 && pd_args.args_count != 2)
return -EINVAL;
idx = pd_args.args[0];
/*
* Check the validity of the requested idx, if the index is not valid
* the PMMC will return a NAK here and we will not allocate it.
*/
ret = ti_sci->ops.dev_ops.is_valid(ti_sci, idx);
if (ret)
return -EINVAL;
sci_dev_data = kzalloc(sizeof(*sci_dev_data), GFP_KERNEL);
if (!sci_dev_data)
return -ENOMEM;
if (idx >= genpd_data->num_domains) {
pr_err("%s: invalid domain index %u\n", __func__, idx);
return ERR_PTR(-EINVAL);
}
sci_dev_data->idx = idx;
/* Enable the exclusive permissions by default */
sci_dev_data->exclusive = TI_SCI_PD_EXCLUSIVE;
if (pd_args.args_count == 2)
sci_dev_data->exclusive = pd_args.args[1] & 0x1;
if (!genpd_data->domains[idx])
return ERR_PTR(-ENOENT);
genpd_data = dev_gpd_data(dev);
genpd_data->data = sci_dev_data;
genpd_to_ti_sci_pd(genpd_data->domains[idx])->exclusive =
genpdspec->args[1];
return 0;
}
static void ti_sci_pd_detach_dev(struct generic_pm_domain *domain,
struct device *dev)
{
struct generic_pm_domain_data *genpd_data = dev_gpd_data(dev);
struct ti_sci_genpd_dev_data *sci_dev_data = genpd_data->data;
kfree(sci_dev_data);
genpd_data->data = NULL;
return genpd_data->domains[idx];
}
static const struct of_device_id ti_sci_pm_domain_matches[] = {
......@@ -173,33 +117,80 @@ MODULE_DEVICE_TABLE(of, ti_sci_pm_domain_matches);
static int ti_sci_pm_domain_probe(struct platform_device *pdev)
{
struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node;
struct ti_sci_pm_domain *ti_sci_pd;
struct ti_sci_genpd_provider *pd_provider;
struct ti_sci_pm_domain *pd;
struct device_node *np = NULL;
struct of_phandle_args args;
int ret;
u32 max_id = 0;
int index;
ti_sci_pd = devm_kzalloc(dev, sizeof(*ti_sci_pd), GFP_KERNEL);
if (!ti_sci_pd)
pd_provider = devm_kzalloc(dev, sizeof(*pd_provider), GFP_KERNEL);
if (!pd_provider)
return -ENOMEM;
ti_sci_pd->ti_sci = devm_ti_sci_get_handle(dev);
if (IS_ERR(ti_sci_pd->ti_sci))
return PTR_ERR(ti_sci_pd->ti_sci);
pd_provider->ti_sci = devm_ti_sci_get_handle(dev);
if (IS_ERR(pd_provider->ti_sci))
return PTR_ERR(pd_provider->ti_sci);
pd_provider->dev = dev;
INIT_LIST_HEAD(&pd_provider->pd_list);
/* Find highest device ID used for power domains */
while (1) {
np = of_find_node_with_property(np, "power-domains");
if (!np)
break;
index = 0;
while (1) {
ret = of_parse_phandle_with_args(np, "power-domains",
"#power-domain-cells",
index, &args);
if (ret)
break;
if (args.args_count >= 1 && args.np == dev->of_node) {
if (args.args[0] > max_id)
max_id = args.args[0];
pd = devm_kzalloc(dev, sizeof(*pd), GFP_KERNEL);
if (!pd)
return -ENOMEM;
pd->pd.name = devm_kasprintf(dev, GFP_KERNEL,
"pd:%d",
args.args[0]);
if (!pd->pd.name)
return -ENOMEM;
ti_sci_pd->dev = dev;
pd->pd.power_off = ti_sci_pd_power_off;
pd->pd.power_on = ti_sci_pd_power_on;
pd->idx = args.args[0];
pd->parent = pd_provider;
ti_sci_pd->pd.name = "ti_sci_pd";
pm_genpd_init(&pd->pd, NULL, true);
ti_sci_pd->pd.attach_dev = ti_sci_pd_attach_dev;
ti_sci_pd->pd.detach_dev = ti_sci_pd_detach_dev;
list_add(&pd->node, &pd_provider->pd_list);
}
index++;
}
}
ti_sci_pd->pd.dev_ops.start = ti_sci_dev_start;
ti_sci_pd->pd.dev_ops.stop = ti_sci_dev_stop;
pd_provider->data.domains =
devm_kcalloc(dev, max_id + 1,
sizeof(*pd_provider->data.domains),
GFP_KERNEL);
pm_genpd_init(&ti_sci_pd->pd, NULL, true);
pd_provider->data.num_domains = max_id + 1;
pd_provider->data.xlate = ti_sci_pd_xlate;
ret = of_genpd_add_provider_simple(np, &ti_sci_pd->pd);
list_for_each_entry(pd, &pd_provider->pd_list, node)
pd_provider->data.domains[pd->idx] = &pd->pd;
return ret;
return of_genpd_add_provider_onecell(dev->of_node, &pd_provider->data);
}
static struct platform_driver ti_sci_pm_domains_driver = {
......
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* PRU-ICSS sub-system specific definitions
*
* Copyright (C) 2014-2020 Texas Instruments Incorporated - http://www.ti.com/
* Suman Anna <s-anna@ti.com>
*/
#ifndef _PRUSS_DRIVER_H_
#define _PRUSS_DRIVER_H_
#include <linux/types.h>
/*
* enum pruss_mem - PRUSS memory range identifiers
*/
enum pruss_mem {
PRUSS_MEM_DRAM0 = 0,
PRUSS_MEM_DRAM1,
PRUSS_MEM_SHRD_RAM2,
PRUSS_MEM_MAX,
};
/**
* struct pruss_mem_region - PRUSS memory region structure
* @va: kernel virtual address of the PRUSS memory region
* @pa: physical (bus) address of the PRUSS memory region
* @size: size of the PRUSS memory region
*/
struct pruss_mem_region {
void __iomem *va;
phys_addr_t pa;
size_t size;
};
/**
* struct pruss - PRUSS parent structure
* @dev: pruss device pointer
* @cfg_base: base iomap for CFG region
* @cfg_regmap: regmap for config region
* @mem_regions: data for each of the PRUSS memory regions
* @core_clk_mux: clk handle for PRUSS CORE_CLK_MUX
* @iep_clk_mux: clk handle for PRUSS IEP_CLK_MUX
*/
struct pruss {
struct device *dev;
void __iomem *cfg_base;
struct regmap *cfg_regmap;
struct pruss_mem_region mem_regions[PRUSS_MEM_MAX];
struct clk *core_clk_mux;
struct clk *iep_clk_mux;
};
#endif /* _PRUSS_DRIVER_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment