0001
0002
0003
0004
0005
0006
0007 #include <linux/io.h>
0008 #include <linux/fsl/mc.h>
0009
0010 #include "fsl-mc-private.h"
0011
0012 static int fsl_mc_io_set_dpmcp(struct fsl_mc_io *mc_io,
0013 struct fsl_mc_device *dpmcp_dev)
0014 {
0015 int error;
0016
0017 if (mc_io->dpmcp_dev)
0018 return -EINVAL;
0019
0020 if (dpmcp_dev->mc_io)
0021 return -EINVAL;
0022
0023 error = dpmcp_open(mc_io,
0024 0,
0025 dpmcp_dev->obj_desc.id,
0026 &dpmcp_dev->mc_handle);
0027 if (error < 0)
0028 return error;
0029
0030 mc_io->dpmcp_dev = dpmcp_dev;
0031 dpmcp_dev->mc_io = mc_io;
0032 return 0;
0033 }
0034
0035 static void fsl_mc_io_unset_dpmcp(struct fsl_mc_io *mc_io)
0036 {
0037 int error;
0038 struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev;
0039
0040 error = dpmcp_close(mc_io,
0041 0,
0042 dpmcp_dev->mc_handle);
0043 if (error < 0) {
0044 dev_err(&dpmcp_dev->dev, "dpmcp_close() failed: %d\n",
0045 error);
0046 }
0047
0048 mc_io->dpmcp_dev = NULL;
0049 dpmcp_dev->mc_io = NULL;
0050 }
0051
0052
0053
0054
0055
0056
0057
0058
0059
0060
0061
0062
0063
0064
0065 int __must_check fsl_create_mc_io(struct device *dev,
0066 phys_addr_t mc_portal_phys_addr,
0067 u32 mc_portal_size,
0068 struct fsl_mc_device *dpmcp_dev,
0069 u32 flags, struct fsl_mc_io **new_mc_io)
0070 {
0071 int error;
0072 struct fsl_mc_io *mc_io;
0073 void __iomem *mc_portal_virt_addr;
0074 struct resource *res;
0075
0076 mc_io = devm_kzalloc(dev, sizeof(*mc_io), GFP_KERNEL);
0077 if (!mc_io)
0078 return -ENOMEM;
0079
0080 mc_io->dev = dev;
0081 mc_io->flags = flags;
0082 mc_io->portal_phys_addr = mc_portal_phys_addr;
0083 mc_io->portal_size = mc_portal_size;
0084 if (flags & FSL_MC_IO_ATOMIC_CONTEXT_PORTAL)
0085 raw_spin_lock_init(&mc_io->spinlock);
0086 else
0087 mutex_init(&mc_io->mutex);
0088
0089 res = devm_request_mem_region(dev,
0090 mc_portal_phys_addr,
0091 mc_portal_size,
0092 "mc_portal");
0093 if (!res) {
0094 dev_err(dev,
0095 "devm_request_mem_region failed for MC portal %pa\n",
0096 &mc_portal_phys_addr);
0097 return -EBUSY;
0098 }
0099
0100 mc_portal_virt_addr = devm_ioremap(dev,
0101 mc_portal_phys_addr,
0102 mc_portal_size);
0103 if (!mc_portal_virt_addr) {
0104 dev_err(dev,
0105 "devm_ioremap failed for MC portal %pa\n",
0106 &mc_portal_phys_addr);
0107 return -ENXIO;
0108 }
0109
0110 mc_io->portal_virt_addr = mc_portal_virt_addr;
0111 if (dpmcp_dev) {
0112 error = fsl_mc_io_set_dpmcp(mc_io, dpmcp_dev);
0113 if (error < 0)
0114 goto error_destroy_mc_io;
0115 }
0116
0117 *new_mc_io = mc_io;
0118 return 0;
0119
0120 error_destroy_mc_io:
0121 fsl_destroy_mc_io(mc_io);
0122 return error;
0123 }
0124
0125
0126
0127
0128
0129
0130 void fsl_destroy_mc_io(struct fsl_mc_io *mc_io)
0131 {
0132 struct fsl_mc_device *dpmcp_dev;
0133
0134 if (!mc_io)
0135 return;
0136
0137 dpmcp_dev = mc_io->dpmcp_dev;
0138
0139 if (dpmcp_dev)
0140 fsl_mc_io_unset_dpmcp(mc_io);
0141
0142 devm_iounmap(mc_io->dev, mc_io->portal_virt_addr);
0143 devm_release_mem_region(mc_io->dev,
0144 mc_io->portal_phys_addr,
0145 mc_io->portal_size);
0146
0147 mc_io->portal_virt_addr = NULL;
0148 devm_kfree(mc_io->dev, mc_io);
0149 }
0150
0151
0152
0153
0154
0155
0156
0157
0158
0159
0160
0161
0162
0163
0164
0165 int __must_check fsl_mc_portal_allocate(struct fsl_mc_device *mc_dev,
0166 u16 mc_io_flags,
0167 struct fsl_mc_io **new_mc_io)
0168 {
0169 struct fsl_mc_device *mc_bus_dev;
0170 struct fsl_mc_bus *mc_bus;
0171 phys_addr_t mc_portal_phys_addr;
0172 size_t mc_portal_size;
0173 struct fsl_mc_device *dpmcp_dev;
0174 int error = -EINVAL;
0175 struct fsl_mc_resource *resource = NULL;
0176 struct fsl_mc_io *mc_io = NULL;
0177
0178 if (mc_dev->flags & FSL_MC_IS_DPRC) {
0179 mc_bus_dev = mc_dev;
0180 } else {
0181 if (!dev_is_fsl_mc(mc_dev->dev.parent))
0182 return error;
0183
0184 mc_bus_dev = to_fsl_mc_device(mc_dev->dev.parent);
0185 }
0186
0187 mc_bus = to_fsl_mc_bus(mc_bus_dev);
0188 *new_mc_io = NULL;
0189 error = fsl_mc_resource_allocate(mc_bus, FSL_MC_POOL_DPMCP, &resource);
0190 if (error < 0)
0191 return error;
0192
0193 error = -EINVAL;
0194 dpmcp_dev = resource->data;
0195
0196 if (dpmcp_dev->obj_desc.ver_major < DPMCP_MIN_VER_MAJOR ||
0197 (dpmcp_dev->obj_desc.ver_major == DPMCP_MIN_VER_MAJOR &&
0198 dpmcp_dev->obj_desc.ver_minor < DPMCP_MIN_VER_MINOR)) {
0199 dev_err(&dpmcp_dev->dev,
0200 "ERROR: Version %d.%d of DPMCP not supported.\n",
0201 dpmcp_dev->obj_desc.ver_major,
0202 dpmcp_dev->obj_desc.ver_minor);
0203 error = -ENOTSUPP;
0204 goto error_cleanup_resource;
0205 }
0206
0207 mc_portal_phys_addr = dpmcp_dev->regions[0].start;
0208 mc_portal_size = resource_size(dpmcp_dev->regions);
0209
0210 error = fsl_create_mc_io(&mc_bus_dev->dev,
0211 mc_portal_phys_addr,
0212 mc_portal_size, dpmcp_dev,
0213 mc_io_flags, &mc_io);
0214 if (error < 0)
0215 goto error_cleanup_resource;
0216
0217 dpmcp_dev->consumer_link = device_link_add(&mc_dev->dev,
0218 &dpmcp_dev->dev,
0219 DL_FLAG_AUTOREMOVE_CONSUMER);
0220 if (!dpmcp_dev->consumer_link) {
0221 error = -EINVAL;
0222 goto error_cleanup_mc_io;
0223 }
0224
0225 *new_mc_io = mc_io;
0226 return 0;
0227
0228 error_cleanup_mc_io:
0229 fsl_destroy_mc_io(mc_io);
0230 error_cleanup_resource:
0231 fsl_mc_resource_free(resource);
0232 return error;
0233 }
0234 EXPORT_SYMBOL_GPL(fsl_mc_portal_allocate);
0235
0236
0237
0238
0239
0240
0241
0242 void fsl_mc_portal_free(struct fsl_mc_io *mc_io)
0243 {
0244 struct fsl_mc_device *dpmcp_dev;
0245 struct fsl_mc_resource *resource;
0246
0247
0248
0249
0250
0251 dpmcp_dev = mc_io->dpmcp_dev;
0252
0253 resource = dpmcp_dev->resource;
0254 if (!resource || resource->type != FSL_MC_POOL_DPMCP)
0255 return;
0256
0257 if (resource->data != dpmcp_dev)
0258 return;
0259
0260 fsl_destroy_mc_io(mc_io);
0261 fsl_mc_resource_free(resource);
0262
0263 dpmcp_dev->consumer_link = NULL;
0264 }
0265 EXPORT_SYMBOL_GPL(fsl_mc_portal_free);
0266
0267
0268
0269
0270
0271
0272 int fsl_mc_portal_reset(struct fsl_mc_io *mc_io)
0273 {
0274 int error;
0275 struct fsl_mc_device *dpmcp_dev = mc_io->dpmcp_dev;
0276
0277 error = dpmcp_reset(mc_io, 0, dpmcp_dev->mc_handle);
0278 if (error < 0) {
0279 dev_err(&dpmcp_dev->dev, "dpmcp_reset() failed: %d\n", error);
0280 return error;
0281 }
0282
0283 return 0;
0284 }
0285 EXPORT_SYMBOL_GPL(fsl_mc_portal_reset);