blob: e3bb2ede554aae7c479ba26c29d5f93426f067ed [file] [log] [blame]
Keerthyb3ab56c2021-06-22 12:04:27 +05301// SPDX-License-Identifier: GPL-2.0
2/*
3 * PRU-ICSS platform driver for various TI SoCs
4 *
5 * Copyright (C) 2020-2021 Texas Instruments Incorporated - https://www.ti.com/
6 */
7
Keerthyb3ab56c2021-06-22 12:04:27 +05308#include <dm.h>
9#include <dm/of_access.h>
10#include <errno.h>
11#include <clk.h>
12#include <reset.h>
13#include <regmap.h>
14#include <syscon.h>
15#include <asm/io.h>
16#include <power-domain.h>
17#include <linux/pruss_driver.h>
18#include <dm/device_compat.h>
19
20#define PRUSS_CFG_IEPCLK 0x30
21#define ICSSG_CFG_CORE_SYNC 0x3c
22
23#define ICSSG_TASK_MGR_OFFSET 0x2a000
24
25/* PRUSS_IEPCLK register bits */
26#define PRUSS_IEPCLK_IEP_OCP_CLK_EN BIT(0)
27
28/* ICSSG CORE_SYNC register bits */
29#define ICSSG_CORE_VBUSP_SYNC_EN BIT(0)
30
31/*
32 * pruss_request_tm_region() - Request pruss for task manager region
33 * @dev: corresponding k3 device
34 * @loc: the task manager physical address
35 *
36 * Return: 0 if all goes good, else appropriate error message.
37 */
38int pruss_request_tm_region(struct udevice *dev, phys_addr_t *loc)
39{
40 struct pruss *priv;
41
42 priv = dev_get_priv(dev);
43 if (!priv || !priv->mem_regions[PRUSS_MEM_DRAM0].pa)
44 return -EINVAL;
45
46 *loc = priv->mem_regions[PRUSS_MEM_DRAM0].pa + ICSSG_TASK_MGR_OFFSET;
47
48 return 0;
49}
50
51/**
52 * pruss_request_mem_region() - request a memory resource
53 * @dev: the pruss device
54 * @mem_id: the memory resource id
55 * @region: pointer to memory region structure to be filled in
56 *
57 * This function allows a client driver to request a memory resource,
58 * and if successful, will let the client driver own the particular
59 * memory region until released using the pruss_release_mem_region()
60 * API.
61 *
62 * Returns the memory region if requested resource is available, an
63 * error otherwise
64 */
65int pruss_request_mem_region(struct udevice *dev, enum pruss_mem mem_id,
66 struct pruss_mem_region *region)
67{
68 struct pruss *pruss;
69
70 pruss = dev_get_priv(dev);
71 if (!pruss || !region)
72 return -EINVAL;
73
74 if (mem_id >= PRUSS_MEM_MAX)
75 return -EINVAL;
76
77 if (pruss->mem_in_use[mem_id])
78 return -EBUSY;
79
80 *region = pruss->mem_regions[mem_id];
81 pruss->mem_in_use[mem_id] = region;
82
83 return 0;
84}
85
86/**
87 * pruss_release_mem_region() - release a memory resource
88 * @dev: the pruss device
89 * @region: the memory region to release
90 *
91 * This function is the complimentary function to
92 * pruss_request_mem_region(), and allows the client drivers to
93 * release back a memory resource.
94 *
95 * Returns 0 on success, an error code otherwise
96 */
97int pruss_release_mem_region(struct udevice *dev,
98 struct pruss_mem_region *region)
99{
100 struct pruss *pruss;
101 int id;
102
103 pruss = dev_get_priv(dev);
104 if (!pruss || !region)
105 return -EINVAL;
106
107 /* find out the memory region being released */
108 for (id = 0; id < PRUSS_MEM_MAX; id++) {
109 if (pruss->mem_in_use[id] == region)
110 break;
111 }
112
113 if (id == PRUSS_MEM_MAX)
114 return -EINVAL;
115
116 pruss->mem_in_use[id] = NULL;
117
118 return 0;
119}
120
121/**
122 * pruss_cfg_update() - configure a PRUSS CFG sub-module register
123 * @dev: the pruss device
124 * @reg: register offset within the CFG sub-module
125 * @mask: bit mask to use for programming the @val
126 * @val: value to write
127 *
128 * Programs a given register within the PRUSS CFG sub-module
129 *
130 * Returns 0 on success, or an error code otherwise
131 */
132int pruss_cfg_update(struct udevice *dev, unsigned int reg,
133 unsigned int mask, unsigned int val)
134{
135 struct pruss *pruss;
136
137 pruss = dev_get_priv(dev);
138 if (IS_ERR_OR_NULL(pruss))
139 return -EINVAL;
140
141 return regmap_update_bits(pruss->cfg, reg, mask, val);
142}
143
144/**
145 * pruss_probe() - Basic probe
146 * @dev: corresponding k3 device
147 *
148 * Return: 0 if all goes good, else appropriate error message.
149 */
150static int pruss_probe(struct udevice *dev)
151{
152 const char *mem_names[PRUSS_MEM_MAX] = { "dram0", "dram1", "shrdram2" };
153 ofnode sub_node, node, memories;
154 struct udevice *syscon;
155 struct pruss *priv;
156 int ret, idx, i;
157
158 priv = dev_get_priv(dev);
159 node = dev_ofnode(dev);
160 priv->dev = dev;
161 memories = ofnode_find_subnode(node, "memories");
162
163 for (i = 0; i < ARRAY_SIZE(mem_names); i++) {
164 idx = ofnode_stringlist_search(memories, "reg-names", mem_names[i]);
165 priv->mem_regions[i].pa = ofnode_get_addr_size_index(memories, idx,
166 (u64 *)&priv->mem_regions[i].size);
167 }
168
169 sub_node = ofnode_find_subnode(node, "cfg");
170 ret = uclass_get_device_by_ofnode(UCLASS_SYSCON, sub_node,
171 &syscon);
172
173 priv->cfg = syscon_get_regmap(syscon);
174 if (IS_ERR(priv->cfg)) {
175 dev_err(dev, "unable to get cfg regmap (%ld)\n",
176 PTR_ERR(priv->cfg));
177 return -ENODEV;
178 }
179
180 /*
181 * ToDo: To be modelled as clocks.
182 * The CORE block uses two multiplexers to allow software to
183 * select one of three source clocks (ICSSGn_CORE_CLK, ICSSGn_ICLK or
184 * ICSSGn_IEP_CLK) for the final clock source of the CORE block.
185 * The user needs to configure ICSSG_CORE_SYNC_REG[0] CORE_VBUSP_SYNC_EN
186 * bit & ICSSG_IEPCLK_REG[0] IEP_OCP_CLK_EN bit in order to select the
187 * clock source to the CORE block.
188 */
189 ret = regmap_update_bits(priv->cfg, ICSSG_CFG_CORE_SYNC,
190 ICSSG_CORE_VBUSP_SYNC_EN,
191 ICSSG_CORE_VBUSP_SYNC_EN);
192 if (ret)
193 return ret;
194 ret = regmap_update_bits(priv->cfg, PRUSS_CFG_IEPCLK,
195 PRUSS_IEPCLK_IEP_OCP_CLK_EN,
196 PRUSS_IEPCLK_IEP_OCP_CLK_EN);
197 if (ret)
198 return ret;
199
200 dev_dbg(dev, "pruss successfully probed %s\n", dev->name);
201
202 return 0;
203}
204
205static const struct udevice_id pruss_ids[] = {
206 { .compatible = "ti,am654-icssg"},
Tom Rinidec7ea02024-05-20 13:35:03 -0600207 { .compatible = "ti,am642-icssg"},
Keerthyb3ab56c2021-06-22 12:04:27 +0530208 {}
209};
210
211U_BOOT_DRIVER(pruss) = {
212 .name = "pruss",
213 .of_match = pruss_ids,
214 .id = UCLASS_MISC,
215 .probe = pruss_probe,
216 .priv_auto = sizeof(struct pruss),
217};