66 * Author(s):
77 * Suman Anna <s-anna@ti.com>
88 * Andrew F. Davis <afd@ti.com>
9+ * Tero Kristo <t-kristo@ti.com>
910 */
1011
1112#include <linux/clk-provider.h>
1819#include <linux/pm_runtime.h>
1920#include <linux/pruss_driver.h>
2021#include <linux/regmap.h>
22+ #include <linux/remoteproc.h>
2123#include <linux/slab.h>
24+ #include "pruss.h"
2225
2326/**
2427 * struct pruss_private_data - PRUSS driver private data
@@ -30,6 +33,257 @@ struct pruss_private_data {
3033 bool has_core_mux_clock ;
3134};
3235
36+ /**
37+ * pruss_get() - get the pruss for a given PRU remoteproc
38+ * @rproc: remoteproc handle of a PRU instance
39+ *
40+ * Finds the parent pruss device for a PRU given the @rproc handle of the
41+ * PRU remote processor. This function increments the pruss device's refcount,
42+ * so always use pruss_put() to decrement it back once pruss isn't needed
43+ * anymore.
44+ *
45+ * This API doesn't check if @rproc is valid or not. It is expected the caller
46+ * will have done a pru_rproc_get() on @rproc, before calling this API to make
47+ * sure that @rproc is valid.
48+ *
49+ * Return: pruss handle on success, and an ERR_PTR on failure using one
50+ * of the following error values
51+ * -EINVAL if invalid parameter
52+ * -ENODEV if PRU device or PRUSS device is not found
53+ */
54+ struct pruss * pruss_get (struct rproc * rproc )
55+ {
56+ struct pruss * pruss ;
57+ struct device * dev ;
58+ struct platform_device * ppdev ;
59+
60+ if (IS_ERR_OR_NULL (rproc ))
61+ return ERR_PTR (- EINVAL );
62+
63+ dev = & rproc -> dev ;
64+
65+ /* make sure it is PRU rproc */
66+ if (!dev -> parent || !is_pru_rproc (dev -> parent ))
67+ return ERR_PTR (- ENODEV );
68+
69+ ppdev = to_platform_device (dev -> parent -> parent );
70+ pruss = platform_get_drvdata (ppdev );
71+ if (!pruss )
72+ return ERR_PTR (- ENODEV );
73+
74+ get_device (pruss -> dev );
75+
76+ return pruss ;
77+ }
78+ EXPORT_SYMBOL_GPL (pruss_get );
79+
80+ /**
81+ * pruss_put() - decrement pruss device's usecount
82+ * @pruss: pruss handle
83+ *
84+ * Complimentary function for pruss_get(). Needs to be called
85+ * after the PRUSS is used, and only if the pruss_get() succeeds.
86+ */
87+ void pruss_put (struct pruss * pruss )
88+ {
89+ if (IS_ERR_OR_NULL (pruss ))
90+ return ;
91+
92+ put_device (pruss -> dev );
93+ }
94+ EXPORT_SYMBOL_GPL (pruss_put );
95+
96+ /**
97+ * pruss_request_mem_region() - request a memory resource
98+ * @pruss: the pruss instance
99+ * @mem_id: the memory resource id
100+ * @region: pointer to memory region structure to be filled in
101+ *
102+ * This function allows a client driver to request a memory resource,
103+ * and if successful, will let the client driver own the particular
104+ * memory region until released using the pruss_release_mem_region()
105+ * API.
106+ *
107+ * Return: 0 if requested memory region is available (in such case pointer to
108+ * memory region is returned via @region), an error otherwise
109+ */
110+ int pruss_request_mem_region (struct pruss * pruss , enum pruss_mem mem_id ,
111+ struct pruss_mem_region * region )
112+ {
113+ if (!pruss || !region || mem_id >= PRUSS_MEM_MAX )
114+ return - EINVAL ;
115+
116+ mutex_lock (& pruss -> lock );
117+
118+ if (pruss -> mem_in_use [mem_id ]) {
119+ mutex_unlock (& pruss -> lock );
120+ return - EBUSY ;
121+ }
122+
123+ * region = pruss -> mem_regions [mem_id ];
124+ pruss -> mem_in_use [mem_id ] = region ;
125+
126+ mutex_unlock (& pruss -> lock );
127+
128+ return 0 ;
129+ }
130+ EXPORT_SYMBOL_GPL (pruss_request_mem_region );
131+
132+ /**
133+ * pruss_release_mem_region() - release a memory resource
134+ * @pruss: the pruss instance
135+ * @region: the memory region to release
136+ *
137+ * This function is the complimentary function to
138+ * pruss_request_mem_region(), and allows the client drivers to
139+ * release back a memory resource.
140+ *
141+ * Return: 0 on success, an error code otherwise
142+ */
143+ int pruss_release_mem_region (struct pruss * pruss ,
144+ struct pruss_mem_region * region )
145+ {
146+ int id ;
147+
148+ if (!pruss || !region )
149+ return - EINVAL ;
150+
151+ mutex_lock (& pruss -> lock );
152+
153+ /* find out the memory region being released */
154+ for (id = 0 ; id < PRUSS_MEM_MAX ; id ++ ) {
155+ if (pruss -> mem_in_use [id ] == region )
156+ break ;
157+ }
158+
159+ if (id == PRUSS_MEM_MAX ) {
160+ mutex_unlock (& pruss -> lock );
161+ return - EINVAL ;
162+ }
163+
164+ pruss -> mem_in_use [id ] = NULL ;
165+
166+ mutex_unlock (& pruss -> lock );
167+
168+ return 0 ;
169+ }
170+ EXPORT_SYMBOL_GPL (pruss_release_mem_region );
171+
172+ /**
173+ * pruss_cfg_get_gpmux() - get the current GPMUX value for a PRU device
174+ * @pruss: pruss instance
175+ * @pru_id: PRU identifier (0-1)
176+ * @mux: pointer to store the current mux value into
177+ *
178+ * Return: 0 on success, or an error code otherwise
179+ */
180+ int pruss_cfg_get_gpmux (struct pruss * pruss , enum pruss_pru_id pru_id , u8 * mux )
181+ {
182+ int ret ;
183+ u32 val ;
184+
185+ if (pru_id >= PRUSS_NUM_PRUS || !mux )
186+ return - EINVAL ;
187+
188+ ret = pruss_cfg_read (pruss , PRUSS_CFG_GPCFG (pru_id ), & val );
189+ if (!ret )
190+ * mux = (u8 )((val & PRUSS_GPCFG_PRU_MUX_SEL_MASK ) >>
191+ PRUSS_GPCFG_PRU_MUX_SEL_SHIFT );
192+ return ret ;
193+ }
194+ EXPORT_SYMBOL_GPL (pruss_cfg_get_gpmux );
195+
196+ /**
197+ * pruss_cfg_set_gpmux() - set the GPMUX value for a PRU device
198+ * @pruss: pruss instance
199+ * @pru_id: PRU identifier (0-1)
200+ * @mux: new mux value for PRU
201+ *
202+ * Return: 0 on success, or an error code otherwise
203+ */
204+ int pruss_cfg_set_gpmux (struct pruss * pruss , enum pruss_pru_id pru_id , u8 mux )
205+ {
206+ if (mux >= PRUSS_GP_MUX_SEL_MAX ||
207+ pru_id >= PRUSS_NUM_PRUS )
208+ return - EINVAL ;
209+
210+ return pruss_cfg_update (pruss , PRUSS_CFG_GPCFG (pru_id ),
211+ PRUSS_GPCFG_PRU_MUX_SEL_MASK ,
212+ (u32 )mux << PRUSS_GPCFG_PRU_MUX_SEL_SHIFT );
213+ }
214+ EXPORT_SYMBOL_GPL (pruss_cfg_set_gpmux );
215+
216+ /**
217+ * pruss_cfg_gpimode() - set the GPI mode of the PRU
218+ * @pruss: the pruss instance handle
219+ * @pru_id: id of the PRU core within the PRUSS
220+ * @mode: GPI mode to set
221+ *
222+ * Sets the GPI mode for a given PRU by programming the
223+ * corresponding PRUSS_CFG_GPCFGx register
224+ *
225+ * Return: 0 on success, or an error code otherwise
226+ */
227+ int pruss_cfg_gpimode (struct pruss * pruss , enum pruss_pru_id pru_id ,
228+ enum pruss_gpi_mode mode )
229+ {
230+ if (pru_id >= PRUSS_NUM_PRUS || mode >= PRUSS_GPI_MODE_MAX )
231+ return - EINVAL ;
232+
233+ return pruss_cfg_update (pruss , PRUSS_CFG_GPCFG (pru_id ),
234+ PRUSS_GPCFG_PRU_GPI_MODE_MASK ,
235+ mode << PRUSS_GPCFG_PRU_GPI_MODE_SHIFT );
236+ }
237+ EXPORT_SYMBOL_GPL (pruss_cfg_gpimode );
238+
239+ /**
240+ * pruss_cfg_miirt_enable() - Enable/disable MII RT Events
241+ * @pruss: the pruss instance
242+ * @enable: enable/disable
243+ *
244+ * Enable/disable the MII RT Events for the PRUSS.
245+ *
246+ * Return: 0 on success, or an error code otherwise
247+ */
248+ int pruss_cfg_miirt_enable (struct pruss * pruss , bool enable )
249+ {
250+ u32 set = enable ? PRUSS_MII_RT_EVENT_EN : 0 ;
251+
252+ return pruss_cfg_update (pruss , PRUSS_CFG_MII_RT ,
253+ PRUSS_MII_RT_EVENT_EN , set );
254+ }
255+ EXPORT_SYMBOL_GPL (pruss_cfg_miirt_enable );
256+
257+ /**
258+ * pruss_cfg_xfr_enable() - Enable/disable XIN XOUT shift functionality
259+ * @pruss: the pruss instance
260+ * @pru_type: PRU core type identifier
261+ * @enable: enable/disable
262+ *
263+ * Return: 0 on success, or an error code otherwise
264+ */
265+ int pruss_cfg_xfr_enable (struct pruss * pruss , enum pru_type pru_type ,
266+ bool enable )
267+ {
268+ u32 mask , set ;
269+
270+ switch (pru_type ) {
271+ case PRU_TYPE_PRU :
272+ mask = PRUSS_SPP_XFER_SHIFT_EN ;
273+ break ;
274+ case PRU_TYPE_RTU :
275+ mask = PRUSS_SPP_RTU_XFR_SHIFT_EN ;
276+ break ;
277+ default :
278+ return - EINVAL ;
279+ }
280+
281+ set = enable ? mask : 0 ;
282+
283+ return pruss_cfg_update (pruss , PRUSS_CFG_SPP , mask , set );
284+ }
285+ EXPORT_SYMBOL_GPL (pruss_cfg_xfr_enable );
286+
33287static void pruss_of_free_clk_provider (void * data )
34288{
35289 struct device_node * clk_mux_np = data ;
@@ -38,6 +292,11 @@ static void pruss_of_free_clk_provider(void *data)
38292 of_node_put (clk_mux_np );
39293}
40294
295+ static void pruss_clk_unregister_mux (void * data )
296+ {
297+ clk_unregister_mux (data );
298+ }
299+
41300static int pruss_clk_mux_setup (struct pruss * pruss , struct clk * clk_mux ,
42301 char * mux_name , struct device_node * clks_np )
43302{
@@ -93,8 +352,7 @@ static int pruss_clk_mux_setup(struct pruss *pruss, struct clk *clk_mux,
93352 goto put_clk_mux_np ;
94353 }
95354
96- ret = devm_add_action_or_reset (dev , (void (* )(void * ))clk_unregister_mux ,
97- clk_mux );
355+ ret = devm_add_action_or_reset (dev , pruss_clk_unregister_mux , clk_mux );
98356 if (ret ) {
99357 dev_err (dev , "failed to add clkmux unregister action %d" , ret );
100358 goto put_clk_mux_np ;
@@ -232,6 +490,7 @@ static int pruss_probe(struct platform_device *pdev)
232490 return - ENOMEM ;
233491
234492 pruss -> dev = dev ;
493+ mutex_init (& pruss -> lock );
235494
236495 child = of_get_child_by_name (np , "memories" );
237496 if (!child ) {
0 commit comments