0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042 #include <linux/module.h>
0043 #include <linux/device.h>
0044 #include <linux/string.h>
0045 #include <linux/slab.h>
0046 #include <linux/platform_device.h>
0047 #include <linux/uio_driver.h>
0048 #include <linux/of_address.h>
0049 #include <linux/of_irq.h>
0050
0051 #include <asm/fsl_lbc.h>
0052
0053 #define MAX_BANKS 8
0054
0055 struct fsl_elbc_gpcm {
0056 struct device *dev;
0057 struct fsl_lbc_regs __iomem *lbc;
0058 u32 bank;
0059 const char *name;
0060
0061 void (*init)(struct uio_info *info);
0062 void (*shutdown)(struct uio_info *info, bool init_err);
0063 irqreturn_t (*irq_handler)(int irq, struct uio_info *info);
0064 };
0065
0066 static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
0067 char *buf);
0068 static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
0069 const char *buf, size_t count);
0070
0071 static DEVICE_ATTR(reg_br, 0664, reg_show, reg_store);
0072 static DEVICE_ATTR(reg_or, 0664, reg_show, reg_store);
0073
0074 static struct attribute *uio_fsl_elbc_gpcm_attrs[] = {
0075 &dev_attr_reg_br.attr,
0076 &dev_attr_reg_or.attr,
0077 NULL,
0078 };
0079 ATTRIBUTE_GROUPS(uio_fsl_elbc_gpcm);
0080
0081 static ssize_t reg_show(struct device *dev, struct device_attribute *attr,
0082 char *buf)
0083 {
0084 struct uio_info *info = dev_get_drvdata(dev);
0085 struct fsl_elbc_gpcm *priv = info->priv;
0086 struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];
0087
0088 if (attr == &dev_attr_reg_br) {
0089 return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
0090 in_be32(&bank->br));
0091
0092 } else if (attr == &dev_attr_reg_or) {
0093 return scnprintf(buf, PAGE_SIZE, "0x%08x\n",
0094 in_be32(&bank->or));
0095 }
0096
0097 return 0;
0098 }
0099
0100 static ssize_t reg_store(struct device *dev, struct device_attribute *attr,
0101 const char *buf, size_t count)
0102 {
0103 struct uio_info *info = dev_get_drvdata(dev);
0104 struct fsl_elbc_gpcm *priv = info->priv;
0105 struct fsl_lbc_bank *bank = &priv->lbc->bank[priv->bank];
0106 unsigned long val;
0107 u32 reg_br_cur;
0108 u32 reg_or_cur;
0109 u32 reg_new;
0110
0111
0112 if (kstrtoul(buf, 0, &val) != 0)
0113 return -EINVAL;
0114 reg_new = (u32)val;
0115
0116
0117 reg_br_cur = in_be32(&bank->br);
0118 reg_or_cur = in_be32(&bank->or);
0119
0120 if (attr == &dev_attr_reg_br) {
0121
0122 if ((reg_br_cur & reg_or_cur & BR_BA) !=
0123 (reg_new & reg_or_cur & BR_BA)) {
0124 return -EINVAL;
0125 }
0126
0127
0128 if ((reg_new & BR_MSEL) != BR_MS_GPCM)
0129 return -EINVAL;
0130
0131
0132 out_be32(&bank->br, reg_new | BR_V);
0133
0134 } else if (attr == &dev_attr_reg_or) {
0135
0136 if ((reg_or_cur & OR_GPCM_AM) != (reg_new & OR_GPCM_AM))
0137 return -EINVAL;
0138
0139
0140 out_be32(&bank->or, reg_new);
0141
0142 } else {
0143 return -EINVAL;
0144 }
0145
0146 return count;
0147 }
0148
0149 #ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152
0150 #define DPM_HOST_WIN0_OFFSET 0xff00
0151 #define DPM_HOST_INT_STAT0 0xe0
0152 #define DPM_HOST_INT_EN0 0xf0
0153 #define DPM_HOST_INT_MASK 0xe600ffff
0154 #define DPM_HOST_INT_GLOBAL_EN 0x80000000
0155
0156 static irqreturn_t netx5152_irq_handler(int irq, struct uio_info *info)
0157 {
0158 void __iomem *reg_int_en = info->mem[0].internal_addr +
0159 DPM_HOST_WIN0_OFFSET +
0160 DPM_HOST_INT_EN0;
0161 void __iomem *reg_int_stat = info->mem[0].internal_addr +
0162 DPM_HOST_WIN0_OFFSET +
0163 DPM_HOST_INT_STAT0;
0164
0165
0166 if ((ioread32(reg_int_en) & ioread32(reg_int_stat) &
0167 DPM_HOST_INT_MASK) == 0) {
0168 return IRQ_NONE;
0169 }
0170
0171
0172 iowrite32(ioread32(reg_int_en) & ~DPM_HOST_INT_GLOBAL_EN, reg_int_en);
0173
0174 return IRQ_HANDLED;
0175 }
0176
0177 static void netx5152_init(struct uio_info *info)
0178 {
0179 unsigned long win0_offset = DPM_HOST_WIN0_OFFSET;
0180 struct fsl_elbc_gpcm *priv = info->priv;
0181 const void *prop;
0182
0183
0184 prop = of_get_property(priv->dev->of_node,
0185 "netx5152,init-win0-offset", NULL);
0186 if (prop)
0187 win0_offset = of_read_ulong(prop, 1);
0188
0189
0190 iowrite32(0, info->mem[0].internal_addr + win0_offset +
0191 DPM_HOST_INT_EN0);
0192 }
0193
0194 static void netx5152_shutdown(struct uio_info *info, bool init_err)
0195 {
0196 if (init_err)
0197 return;
0198
0199
0200 iowrite32(0, info->mem[0].internal_addr + DPM_HOST_WIN0_OFFSET +
0201 DPM_HOST_INT_EN0);
0202 }
0203 #endif
0204
0205 static void setup_periph(struct fsl_elbc_gpcm *priv,
0206 const char *type)
0207 {
0208 #ifdef CONFIG_UIO_FSL_ELBC_GPCM_NETX5152
0209 if (strcmp(type, "netx5152") == 0) {
0210 priv->irq_handler = netx5152_irq_handler;
0211 priv->init = netx5152_init;
0212 priv->shutdown = netx5152_shutdown;
0213 priv->name = "netX 51/52";
0214 return;
0215 }
0216 #endif
0217 }
0218
0219 static int check_of_data(struct fsl_elbc_gpcm *priv,
0220 struct resource *res,
0221 u32 reg_br, u32 reg_or)
0222 {
0223
0224 if (priv->bank >= MAX_BANKS) {
0225 dev_err(priv->dev, "invalid bank\n");
0226 return -ENODEV;
0227 }
0228
0229
0230 if ((reg_br & BR_MSEL) != BR_MS_GPCM) {
0231 dev_err(priv->dev, "unsupported mode\n");
0232 return -ENODEV;
0233 }
0234
0235
0236 if ((~(reg_or & OR_GPCM_AM) + 1) != resource_size(res)) {
0237 dev_err(priv->dev, "address mask / size mismatch\n");
0238 return -ENODEV;
0239 }
0240
0241
0242 if ((reg_br & reg_or & BR_BA) != fsl_lbc_addr(res->start)) {
0243 dev_err(priv->dev, "base address mismatch\n");
0244 return -ENODEV;
0245 }
0246
0247 return 0;
0248 }
0249
0250 static int get_of_data(struct fsl_elbc_gpcm *priv, struct device_node *node,
0251 struct resource *res, u32 *reg_br,
0252 u32 *reg_or, unsigned int *irq, char **name)
0253 {
0254 const char *dt_name;
0255 const char *type;
0256 int ret;
0257
0258
0259 ret = of_address_to_resource(node, 0, res);
0260 if (ret) {
0261 dev_err(priv->dev, "failed to get resource\n");
0262 return ret;
0263 }
0264
0265
0266 ret = of_property_read_u32(node, "reg", &priv->bank);
0267 if (ret) {
0268 dev_err(priv->dev, "failed to get bank number\n");
0269 return ret;
0270 }
0271
0272
0273 ret = of_property_read_u32(node, "elbc-gpcm-br", reg_br);
0274 if (ret) {
0275 dev_err(priv->dev, "missing elbc-gpcm-br value\n");
0276 return ret;
0277 }
0278
0279
0280 ret = of_property_read_u32(node, "elbc-gpcm-or", reg_or);
0281 if (ret) {
0282 dev_err(priv->dev, "missing elbc-gpcm-or value\n");
0283 return ret;
0284 }
0285
0286
0287 priv->name = "generic";
0288 if (of_property_read_string(node, "device_type", &type) == 0)
0289 setup_periph(priv, type);
0290
0291
0292 *irq = irq_of_parse_and_map(node, 0);
0293
0294
0295 ret = check_of_data(priv, res, *reg_br, *reg_or);
0296 if (ret)
0297 return ret;
0298
0299
0300 if (of_property_read_string(node, "uio_name", &dt_name) != 0)
0301 dt_name = "eLBC_GPCM";
0302 *name = devm_kstrdup(priv->dev, dt_name, GFP_KERNEL);
0303 if (!*name)
0304 return -ENOMEM;
0305
0306 return 0;
0307 }
0308
0309 static int uio_fsl_elbc_gpcm_probe(struct platform_device *pdev)
0310 {
0311 struct device_node *node = pdev->dev.of_node;
0312 struct fsl_elbc_gpcm *priv;
0313 struct uio_info *info;
0314 char *uio_name = NULL;
0315 struct resource res;
0316 unsigned int irq;
0317 u32 reg_br_cur;
0318 u32 reg_or_cur;
0319 u32 reg_br_new;
0320 u32 reg_or_new;
0321 int ret;
0322
0323 if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs)
0324 return -ENODEV;
0325
0326
0327 priv = devm_kzalloc(&pdev->dev, sizeof(*priv), GFP_KERNEL);
0328 if (!priv)
0329 return -ENOMEM;
0330 priv->dev = &pdev->dev;
0331 priv->lbc = fsl_lbc_ctrl_dev->regs;
0332
0333
0334 ret = get_of_data(priv, node, &res, ®_br_new, ®_or_new,
0335 &irq, &uio_name);
0336 if (ret)
0337 return ret;
0338
0339
0340 info = devm_kzalloc(&pdev->dev, sizeof(*info), GFP_KERNEL);
0341 if (!info)
0342 return -ENOMEM;
0343
0344
0345 reg_br_cur = in_be32(&priv->lbc->bank[priv->bank].br);
0346 reg_or_cur = in_be32(&priv->lbc->bank[priv->bank].or);
0347
0348
0349 if ((reg_br_cur & BR_V)) {
0350 if ((reg_br_cur & BR_MSEL) != BR_MS_GPCM ||
0351 (reg_br_cur & reg_or_cur & BR_BA)
0352 != fsl_lbc_addr(res.start)) {
0353 dev_err(priv->dev,
0354 "bank in use by another peripheral\n");
0355 return -ENODEV;
0356 }
0357
0358
0359 if ((reg_br_cur & ~(BR_BA | BR_V)) !=
0360 (reg_br_new & ~(BR_BA | BR_V))) {
0361 dev_warn(priv->dev,
0362 "modifying BR settings: 0x%08x -> 0x%08x",
0363 reg_br_cur, reg_br_new);
0364 }
0365 if ((reg_or_cur & ~OR_GPCM_AM) != (reg_or_new & ~OR_GPCM_AM)) {
0366 dev_warn(priv->dev,
0367 "modifying OR settings: 0x%08x -> 0x%08x",
0368 reg_or_cur, reg_or_new);
0369 }
0370 }
0371
0372
0373 reg_br_new &= ~(BR_BA | BR_MSEL);
0374 reg_br_new |= fsl_lbc_addr(res.start) | BR_MS_GPCM | BR_V;
0375 out_be32(&priv->lbc->bank[priv->bank].or, reg_or_new);
0376 out_be32(&priv->lbc->bank[priv->bank].br, reg_br_new);
0377
0378
0379 info->mem[0].internal_addr = ioremap(res.start, resource_size(&res));
0380 if (!info->mem[0].internal_addr) {
0381 dev_err(priv->dev, "failed to map chip region\n");
0382 return -ENODEV;
0383 }
0384
0385
0386 info->mem[0].name = devm_kasprintf(&pdev->dev, GFP_KERNEL, "%pOFn", node);
0387 info->mem[0].addr = res.start;
0388 info->mem[0].size = resource_size(&res);
0389 info->mem[0].memtype = UIO_MEM_PHYS;
0390 info->priv = priv;
0391 info->name = uio_name;
0392 info->version = "0.0.1";
0393 if (irq != NO_IRQ) {
0394 if (priv->irq_handler) {
0395 info->irq = irq;
0396 info->irq_flags = IRQF_SHARED;
0397 info->handler = priv->irq_handler;
0398 } else {
0399 irq = NO_IRQ;
0400 dev_warn(priv->dev, "ignoring irq, no handler\n");
0401 }
0402 }
0403
0404 if (priv->init)
0405 priv->init(info);
0406
0407
0408 if (uio_register_device(priv->dev, info) != 0) {
0409 dev_err(priv->dev, "UIO registration failed\n");
0410 ret = -ENODEV;
0411 goto out_err2;
0412 }
0413
0414
0415 platform_set_drvdata(pdev, info);
0416
0417 dev_info(priv->dev,
0418 "eLBC/GPCM device (%s) at 0x%llx, bank %d, irq=%d\n",
0419 priv->name, (unsigned long long)res.start, priv->bank,
0420 irq != NO_IRQ ? irq : -1);
0421
0422 return 0;
0423 out_err2:
0424 if (priv->shutdown)
0425 priv->shutdown(info, true);
0426 iounmap(info->mem[0].internal_addr);
0427 return ret;
0428 }
0429
0430 static int uio_fsl_elbc_gpcm_remove(struct platform_device *pdev)
0431 {
0432 struct uio_info *info = platform_get_drvdata(pdev);
0433 struct fsl_elbc_gpcm *priv = info->priv;
0434
0435 platform_set_drvdata(pdev, NULL);
0436 uio_unregister_device(info);
0437 if (priv->shutdown)
0438 priv->shutdown(info, false);
0439 iounmap(info->mem[0].internal_addr);
0440
0441 return 0;
0442
0443 }
0444
0445 static const struct of_device_id uio_fsl_elbc_gpcm_match[] = {
0446 { .compatible = "fsl,elbc-gpcm-uio", },
0447 {}
0448 };
0449 MODULE_DEVICE_TABLE(of, uio_fsl_elbc_gpcm_match);
0450
0451 static struct platform_driver uio_fsl_elbc_gpcm_driver = {
0452 .driver = {
0453 .name = "fsl,elbc-gpcm-uio",
0454 .of_match_table = uio_fsl_elbc_gpcm_match,
0455 .dev_groups = uio_fsl_elbc_gpcm_groups,
0456 },
0457 .probe = uio_fsl_elbc_gpcm_probe,
0458 .remove = uio_fsl_elbc_gpcm_remove,
0459 };
0460 module_platform_driver(uio_fsl_elbc_gpcm_driver);
0461
0462 MODULE_LICENSE("GPL");
0463 MODULE_AUTHOR("John Ogness <john.ogness@linutronix.de>");
0464 MODULE_DESCRIPTION("Freescale Enhanced Local Bus Controller GPCM driver");