1 // SPDX-License-Identifier: (GPL-2.0+ OR BSD-3-Clause)
3 * Copyright 2013-2016 Freescale Semiconductor Inc.
8 #include <linux/fsl/mc.h>
10 #include "fsl-mc-private.h"
12 static int fsl_mc_io_set_dpmcp(struct fsl_mc_io
*mc_io
,
13 struct fsl_mc_device
*dpmcp_dev
)
23 error
= dpmcp_open(mc_io
,
25 dpmcp_dev
->obj_desc
.id
,
26 &dpmcp_dev
->mc_handle
);
30 mc_io
->dpmcp_dev
= dpmcp_dev
;
31 dpmcp_dev
->mc_io
= mc_io
;
35 static void fsl_mc_io_unset_dpmcp(struct fsl_mc_io
*mc_io
)
38 struct fsl_mc_device
*dpmcp_dev
= mc_io
->dpmcp_dev
;
40 error
= dpmcp_close(mc_io
,
42 dpmcp_dev
->mc_handle
);
44 dev_err(&dpmcp_dev
->dev
, "dpmcp_close() failed: %d\n",
48 mc_io
->dpmcp_dev
= NULL
;
49 dpmcp_dev
->mc_io
= NULL
;
53 * Creates an MC I/O object
55 * @dev: device to be associated with the MC I/O object
56 * @mc_portal_phys_addr: physical address of the MC portal to use
57 * @mc_portal_size: size in bytes of the MC portal
58 * @dpmcp-dev: Pointer to the DPMCP object associated with this MC I/O
59 * object or NULL if none.
60 * @flags: flags for the new MC I/O object
61 * @new_mc_io: Area to return pointer to newly created MC I/O object
63 * Returns '0' on Success; Error code otherwise.
65 int __must_check
fsl_create_mc_io(struct device
*dev
,
66 phys_addr_t mc_portal_phys_addr
,
68 struct fsl_mc_device
*dpmcp_dev
,
69 u32 flags
, struct fsl_mc_io
**new_mc_io
)
72 struct fsl_mc_io
*mc_io
;
73 void __iomem
*mc_portal_virt_addr
;
76 mc_io
= devm_kzalloc(dev
, sizeof(*mc_io
), GFP_KERNEL
);
82 mc_io
->portal_phys_addr
= mc_portal_phys_addr
;
83 mc_io
->portal_size
= mc_portal_size
;
84 if (flags
& FSL_MC_IO_ATOMIC_CONTEXT_PORTAL
)
85 raw_spin_lock_init(&mc_io
->spinlock
);
87 mutex_init(&mc_io
->mutex
);
89 res
= devm_request_mem_region(dev
,
95 "devm_request_mem_region failed for MC portal %pa\n",
96 &mc_portal_phys_addr
);
100 mc_portal_virt_addr
= devm_ioremap(dev
,
103 if (!mc_portal_virt_addr
) {
105 "devm_ioremap failed for MC portal %pa\n",
106 &mc_portal_phys_addr
);
110 mc_io
->portal_virt_addr
= mc_portal_virt_addr
;
112 error
= fsl_mc_io_set_dpmcp(mc_io
, dpmcp_dev
);
114 goto error_destroy_mc_io
;
121 fsl_destroy_mc_io(mc_io
);
126 * Destroys an MC I/O object
128 * @mc_io: MC I/O object to destroy
130 void fsl_destroy_mc_io(struct fsl_mc_io
*mc_io
)
132 struct fsl_mc_device
*dpmcp_dev
;
137 dpmcp_dev
= mc_io
->dpmcp_dev
;
140 fsl_mc_io_unset_dpmcp(mc_io
);
142 devm_iounmap(mc_io
->dev
, mc_io
->portal_virt_addr
);
143 devm_release_mem_region(mc_io
->dev
,
144 mc_io
->portal_phys_addr
,
147 mc_io
->portal_virt_addr
= NULL
;
148 devm_kfree(mc_io
->dev
, mc_io
);
152 * fsl_mc_portal_allocate - Allocates an MC portal
154 * @mc_dev: MC device for which the MC portal is to be allocated
155 * @mc_io_flags: Flags for the fsl_mc_io object that wraps the allocated
157 * @new_mc_io: Pointer to area where the pointer to the fsl_mc_io object
158 * that wraps the allocated MC portal is to be returned
160 * This function allocates an MC portal from the device's parent DPRC,
161 * from the corresponding MC bus' pool of MC portals and wraps
162 * it in a new fsl_mc_io object. If 'mc_dev' is a DPRC itself, the
163 * portal is allocated from its own MC bus.
165 int __must_check
fsl_mc_portal_allocate(struct fsl_mc_device
*mc_dev
,
167 struct fsl_mc_io
**new_mc_io
)
169 struct fsl_mc_device
*mc_bus_dev
;
170 struct fsl_mc_bus
*mc_bus
;
171 phys_addr_t mc_portal_phys_addr
;
172 size_t mc_portal_size
;
173 struct fsl_mc_device
*dpmcp_dev
;
175 struct fsl_mc_resource
*resource
= NULL
;
176 struct fsl_mc_io
*mc_io
= NULL
;
178 if (mc_dev
->flags
& FSL_MC_IS_DPRC
) {
181 if (!dev_is_fsl_mc(mc_dev
->dev
.parent
))
184 mc_bus_dev
= to_fsl_mc_device(mc_dev
->dev
.parent
);
187 mc_bus
= to_fsl_mc_bus(mc_bus_dev
);
189 error
= fsl_mc_resource_allocate(mc_bus
, FSL_MC_POOL_DPMCP
, &resource
);
194 dpmcp_dev
= resource
->data
;
196 if (dpmcp_dev
->obj_desc
.ver_major
< DPMCP_MIN_VER_MAJOR
||
197 (dpmcp_dev
->obj_desc
.ver_major
== DPMCP_MIN_VER_MAJOR
&&
198 dpmcp_dev
->obj_desc
.ver_minor
< DPMCP_MIN_VER_MINOR
)) {
199 dev_err(&dpmcp_dev
->dev
,
200 "ERROR: Version %d.%d of DPMCP not supported.\n",
201 dpmcp_dev
->obj_desc
.ver_major
,
202 dpmcp_dev
->obj_desc
.ver_minor
);
204 goto error_cleanup_resource
;
207 mc_portal_phys_addr
= dpmcp_dev
->regions
[0].start
;
208 mc_portal_size
= resource_size(dpmcp_dev
->regions
);
210 error
= fsl_create_mc_io(&mc_bus_dev
->dev
,
212 mc_portal_size
, dpmcp_dev
,
213 mc_io_flags
, &mc_io
);
215 goto error_cleanup_resource
;
217 dpmcp_dev
->consumer_link
= device_link_add(&mc_dev
->dev
,
219 DL_FLAG_AUTOREMOVE_CONSUMER
);
220 if (!dpmcp_dev
->consumer_link
) {
222 goto error_cleanup_mc_io
;
229 fsl_destroy_mc_io(mc_io
);
230 error_cleanup_resource
:
231 fsl_mc_resource_free(resource
);
234 EXPORT_SYMBOL_GPL(fsl_mc_portal_allocate
);
237 * fsl_mc_portal_free - Returns an MC portal to the pool of free MC portals
240 * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free
242 void fsl_mc_portal_free(struct fsl_mc_io
*mc_io
)
244 struct fsl_mc_device
*dpmcp_dev
;
245 struct fsl_mc_resource
*resource
;
248 * Every mc_io obtained by calling fsl_mc_portal_allocate() is supposed
249 * to have a DPMCP object associated with.
251 dpmcp_dev
= mc_io
->dpmcp_dev
;
253 resource
= dpmcp_dev
->resource
;
254 if (!resource
|| resource
->type
!= FSL_MC_POOL_DPMCP
)
257 if (resource
->data
!= dpmcp_dev
)
260 fsl_destroy_mc_io(mc_io
);
261 fsl_mc_resource_free(resource
);
263 dpmcp_dev
->consumer_link
= NULL
;
265 EXPORT_SYMBOL_GPL(fsl_mc_portal_free
);
268 * fsl_mc_portal_reset - Resets the dpmcp object for a given fsl_mc_io object
270 * @mc_io: Pointer to the fsl_mc_io object that wraps the MC portal to free
272 int fsl_mc_portal_reset(struct fsl_mc_io
*mc_io
)
275 struct fsl_mc_device
*dpmcp_dev
= mc_io
->dpmcp_dev
;
277 error
= dpmcp_reset(mc_io
, 0, dpmcp_dev
->mc_handle
);
279 dev_err(&dpmcp_dev
->dev
, "dpmcp_reset() failed: %d\n", error
);
285 EXPORT_SYMBOL_GPL(fsl_mc_portal_reset
);