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: ...@@ -62,11 +62,6 @@ properties:
$ref: /schemas/types.yaml#/definitions/uint32 $ref: /schemas/types.yaml#/definitions/uint32
description: TI-SCI device id of the ring accelerator 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: required:
- compatible - compatible
- reg - reg
...@@ -94,7 +89,6 @@ examples: ...@@ -94,7 +89,6 @@ examples:
reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target"; reg-names = "rt", "fifos", "proxy_gcfg", "proxy_target";
ti,num-rings = <818>; ti,num-rings = <818>;
ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */ ti,sci-rm-range-gp-rings = <0x2>; /* GP ring range */
ti,dma-ring-reset-quirk;
ti,sci = <&dmsc>; ti,sci = <&dmsc>;
ti,sci-dev-id = <187>; ti,sci-dev-id = <187>;
msi-parent = <&inta_main_udmass>; 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, ...@@ -579,8 +579,8 @@ static int k3_udma_glue_cfg_rx_flow(struct k3_udma_glue_rx_channel *rx_chn,
/* request and cfg rings */ /* request and cfg rings */
ret = k3_ringacc_request_rings_pair(rx_chn->common.ringacc, ret = k3_ringacc_request_rings_pair(rx_chn->common.ringacc,
flow_cfg->ring_rxq_id,
flow_cfg->ring_rxfdq0_id, flow_cfg->ring_rxfdq0_id,
flow_cfg->ring_rxq_id,
&flow->ringrxfdq, &flow->ringrxfdq,
&flow->ringrx); &flow->ringrx);
if (ret) { if (ret) {
......
...@@ -1124,7 +1124,8 @@ static int ti_sci_cmd_get_clock(const struct ti_sci_handle *handle, u32 dev_id, ...@@ -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, static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle,
u32 dev_id, u32 clk_id) 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); MSG_CLOCK_SW_STATE_UNREQ);
} }
...@@ -1143,7 +1144,8 @@ static int ti_sci_cmd_idle_clock(const struct ti_sci_handle *handle, ...@@ -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, static int ti_sci_cmd_put_clock(const struct ti_sci_handle *handle,
u32 dev_id, u32 clk_id) 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); MSG_CLOCK_SW_STATE_AUTO);
} }
......
...@@ -101,6 +101,17 @@ config TI_K3_SOCINFO ...@@ -101,6 +101,17 @@ config TI_K3_SOCINFO
platforms to provide information about the SoC family and platforms to provide information about the SoC family and
variant to user space. 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 endif # SOC_TI
config TI_SCI_INTA_MSI_DOMAIN config TI_SCI_INTA_MSI_DOMAIN
......
...@@ -12,3 +12,4 @@ obj-$(CONFIG_TI_SCI_PM_DOMAINS) += ti_sci_pm_domains.o ...@@ -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_SCI_INTA_MSI_DOMAIN) += ti_sci_inta_msi.o
obj-$(CONFIG_TI_K3_RINGACC) += k3-ringacc.o obj-$(CONFIG_TI_K3_RINGACC) += k3-ringacc.o
obj-$(CONFIG_TI_K3_SOCINFO) += k3-socinfo.o obj-$(CONFIG_TI_K3_SOCINFO) += k3-socinfo.o
obj-$(CONFIG_TI_PRUSS) += pruss.o
...@@ -10,6 +10,7 @@ ...@@ -10,6 +10,7 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/sys_soc.h>
#include <linux/soc/ti/k3-ringacc.h> #include <linux/soc/ti/k3-ringacc.h>
#include <linux/soc/ti/ti_sci_protocol.h> #include <linux/soc/ti/ti_sci_protocol.h>
#include <linux/soc/ti/ti_sci_inta_msi.h> #include <linux/soc/ti/ti_sci_inta_msi.h>
...@@ -208,6 +209,15 @@ struct k3_ringacc { ...@@ -208,6 +209,15 @@ struct k3_ringacc {
const struct k3_ringacc_ops *ops; 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) static long k3_ringacc_ring_get_fifo_pos(struct k3_ring *ring)
{ {
return K3_RINGACC_FIFO_WINDOW_SIZE_BYTES - return K3_RINGACC_FIFO_WINDOW_SIZE_BYTES -
...@@ -1051,9 +1061,6 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc) ...@@ -1051,9 +1061,6 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
return ret; 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"); ringacc->tisci = ti_sci_get_by_phandle(node, "ti,sci");
if (IS_ERR(ringacc->tisci)) { if (IS_ERR(ringacc->tisci)) {
ret = PTR_ERR(ringacc->tisci); ret = PTR_ERR(ringacc->tisci);
...@@ -1084,9 +1091,22 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc) ...@@ -1084,9 +1091,22 @@ static int k3_ringacc_probe_dt(struct k3_ringacc *ringacc)
ringacc->rm_gp_range); 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, static int k3_ringacc_init(struct platform_device *pdev,
struct k3_ringacc *ringacc) struct k3_ringacc *ringacc)
{ {
const struct soc_device_attribute *soc;
void __iomem *base_fifo, *base_rt; void __iomem *base_fifo, *base_rt;
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct resource *res; struct resource *res;
...@@ -1103,6 +1123,13 @@ static int k3_ringacc_init(struct platform_device *pdev, ...@@ -1103,6 +1123,13 @@ static int k3_ringacc_init(struct platform_device *pdev,
if (ret) if (ret)
return 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"); res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "rt");
base_rt = devm_ioremap_resource(dev, res); base_rt = devm_ioremap_resource(dev, res);
if (IS_ERR(base_rt)) if (IS_ERR(base_rt))
......
...@@ -39,6 +39,7 @@ static const struct k3_soc_id { ...@@ -39,6 +39,7 @@ static const struct k3_soc_id {
} k3_soc_ids[] = { } k3_soc_ids[] = {
{ 0xBB5A, "AM65X" }, { 0xBB5A, "AM65X" },
{ 0xBB64, "J721E" }, { 0xBB64, "J721E" },
{ 0xBB6D, "J7200" },
}; };
static int static int
......
...@@ -355,7 +355,7 @@ static void dma_debug_show_devices(struct seq_file *s, ...@@ -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; struct knav_dma_device *dma;
...@@ -370,17 +370,7 @@ static int dma_debug_show(struct seq_file *s, void *v) ...@@ -370,17 +370,7 @@ static int dma_debug_show(struct seq_file *s, void *v)
return 0; return 0;
} }
static int knav_dma_debug_open(struct inode *inode, struct file *file) DEFINE_SHOW_ATTRIBUTE(knav_dma_debug);
{
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,
};
static int of_channel_match_helper(struct device_node *np, const char *name, static int of_channel_match_helper(struct device_node *np, const char *name,
const char **dma_instance) const char **dma_instance)
...@@ -778,7 +768,7 @@ static int knav_dma_probe(struct platform_device *pdev) ...@@ -778,7 +768,7 @@ static int knav_dma_probe(struct platform_device *pdev)
} }
debugfs_create_file("knav_dma", S_IFREG | S_IRUGO, NULL, NULL, debugfs_create_file("knav_dma", S_IFREG | S_IRUGO, NULL, NULL,
&knav_dma_debug_ops); &knav_dma_debug_fops);
device_ready = true; device_ready = true;
return ret; return ret;
......
...@@ -478,17 +478,7 @@ static int knav_queue_debug_show(struct seq_file *s, void *v) ...@@ -478,17 +478,7 @@ static int knav_queue_debug_show(struct seq_file *s, void *v)
return 0; return 0;
} }
static int knav_queue_debug_open(struct inode *inode, struct file *file) DEFINE_SHOW_ATTRIBUTE(knav_queue_debug);
{
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,
};
static inline int knav_queue_pdsp_wait(u32 * __iomem addr, unsigned timeout, static inline int knav_queue_pdsp_wait(u32 * __iomem addr, unsigned timeout,
u32 flags) u32 flags)
...@@ -1878,7 +1868,7 @@ static int knav_queue_probe(struct platform_device *pdev) ...@@ -1878,7 +1868,7 @@ static int knav_queue_probe(struct platform_device *pdev)
} }
debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL, debugfs_create_file("qmss", S_IFREG | S_IRUGO, NULL, NULL,
&knav_queue_debug_ops); &knav_queue_debug_fops);
device_ready = true; device_ready = true;
return 0; 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 @@ ...@@ -9,7 +9,6 @@
#include <linux/err.h> #include <linux/err.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/mutex.h>
#include <linux/of.h> #include <linux/of.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/pm_domain.h> #include <linux/pm_domain.h>
...@@ -18,150 +17,95 @@ ...@@ -18,150 +17,95 @@
#include <dt-bindings/soc/ti,sci_pm_domain.h> #include <dt-bindings/soc/ti,sci_pm_domain.h>
/** /**
* struct ti_sci_genpd_dev_data: holds data needed for every device attached * struct ti_sci_genpd_provider: holds common TI SCI genpd provider data
* to this genpd * @ti_sci: handle to TI SCI protocol driver that provides ops to
* @idx: index of the device that identifies it with the system * communicate with system control processor.
* control processor. * @dev: pointer to dev for the driver for devm allocs
* @exclusive: Permissions for exclusive request or shared request of the * @pd_list: list of all the power domains on the device
* device. * @data: onecell data for genpd core
*/ */
struct ti_sci_genpd_dev_data { struct ti_sci_genpd_provider {
int idx; const struct ti_sci_handle *ti_sci;
u8 exclusive; 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 * struct ti_sci_pm_domain: TI specific data needed for power domain
* @ti_sci: handle to TI SCI protocol driver that provides ops to * @idx: index of the device that identifies it with the system
* communicate with system control processor. * control processor.
* @dev: pointer to dev for the driver for devm allocs * @exclusive: Permissions for exclusive request or shared request of the
* device.
* @pd: generic_pm_domain for use with the genpd framework * @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 { struct ti_sci_pm_domain {
const struct ti_sci_handle *ti_sci; int idx;
struct device *dev; u8 exclusive;
struct generic_pm_domain pd; 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) #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 * ti_sci_pd_power_off(): genpd power down hook
* @dev: pointer to device associated with this genpd * @domain: pointer to the powerdomain to power off
*
* 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.
*/ */
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 *pd = genpd_to_ti_sci_pd(domain);
struct ti_sci_pm_domain *ti_sci_genpd = genpd_to_ti_sci_pd(pd); 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 * ti_sci_pd_power_on(): genpd power up hook
* @dev: pointer to device associated with this genpd to be powered on * @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); struct ti_sci_pm_domain *pd = genpd_to_ti_sci_pd(domain);
int idx = ti_sci_dev_id(dev); const struct ti_sci_handle *ti_sci = pd->parent->ti_sci;
if (is_ti_sci_dev_exclusive(dev)) if (pd->exclusive)
return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci, idx); return ti_sci->ops.dev_ops.get_device_exclusive(ti_sci,
pd->idx);
else 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 * ti_sci_pd_xlate(): translation service for TI SCI genpds
* @dev: pointer to device associated with this genpd to be powered off * @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); struct genpd_onecell_data *genpd_data = data;
int idx = ti_sci_dev_id(dev); unsigned int idx = genpdspec->args[0];
return ti_sci->ops.dev_ops.put_device(ti_sci, idx);
}
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 (genpdspec->args_count < 2)
if (!sci_dev_data) return ERR_PTR(-EINVAL);
return -ENOMEM;
sci_dev_data->idx = idx; if (idx >= genpd_data->num_domains) {
/* Enable the exclusive permissions by default */ pr_err("%s: invalid domain index %u\n", __func__, idx);
sci_dev_data->exclusive = TI_SCI_PD_EXCLUSIVE; return ERR_PTR(-EINVAL);
if (pd_args.args_count == 2) }
sci_dev_data->exclusive = pd_args.args[1] & 0x1;
genpd_data = dev_gpd_data(dev); if (!genpd_data->domains[idx])
genpd_data->data = sci_dev_data; return ERR_PTR(-ENOENT);
return 0; genpd_to_ti_sci_pd(genpd_data->domains[idx])->exclusive =
} genpdspec->args[1];
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); return genpd_data->domains[idx];
genpd_data->data = NULL;
} }
static const struct of_device_id ti_sci_pm_domain_matches[] = { static const struct of_device_id ti_sci_pm_domain_matches[] = {
...@@ -173,33 +117,80 @@ MODULE_DEVICE_TABLE(of, 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) static int ti_sci_pm_domain_probe(struct platform_device *pdev)
{ {
struct device *dev = &pdev->dev; struct device *dev = &pdev->dev;
struct device_node *np = dev->of_node; struct ti_sci_genpd_provider *pd_provider;
struct ti_sci_pm_domain *ti_sci_pd; struct ti_sci_pm_domain *pd;
struct device_node *np = NULL;
struct of_phandle_args args;
int ret; int ret;
u32 max_id = 0;
int index;
ti_sci_pd = devm_kzalloc(dev, sizeof(*ti_sci_pd), GFP_KERNEL); pd_provider = devm_kzalloc(dev, sizeof(*pd_provider), GFP_KERNEL);
if (!ti_sci_pd) if (!pd_provider)
return -ENOMEM; return -ENOMEM;
ti_sci_pd->ti_sci = devm_ti_sci_get_handle(dev); pd_provider->ti_sci = devm_ti_sci_get_handle(dev);
if (IS_ERR(ti_sci_pd->ti_sci)) if (IS_ERR(pd_provider->ti_sci))
return PTR_ERR(ti_sci_pd->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; list_add(&pd->node, &pd_provider->pd_list);
ti_sci_pd->pd.detach_dev = ti_sci_pd_detach_dev; }
index++;
}
}
ti_sci_pd->pd.dev_ops.start = ti_sci_dev_start; pd_provider->data.domains =
ti_sci_pd->pd.dev_ops.stop = ti_sci_dev_stop; 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 = { 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