/** * fsl_lbc_addr - convert the base address * @addr_base: base address of the memory bank * * This function converts a base address of lbc into the right format for the * BR register. If the SOC has eLBC then it returns 32bit physical address * else it converts a 34bit local bus physical address to correct format of * 32bit address for BR register (Example: MPC8641).
*/
u32 fsl_lbc_addr(phys_addr_t addr_base)
{ struct device_node *np = fsl_lbc_ctrl_dev->dev->of_node;
u32 addr = addr_base & 0xffff8000;
if (of_device_is_compatible(np, "fsl,elbc")) return addr;
/** * fsl_lbc_find - find Localbus bank * @addr_base: base address of the memory bank * * This function walks LBC banks comparing "Base address" field of the BR * registers with the supplied addr_base argument. When bases match this * function returns bank number (starting with 0), otherwise it returns * appropriate errno value.
*/ int fsl_lbc_find(phys_addr_t addr_base)
{ int i; struct fsl_lbc_regs __iomem *lbc;
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) return -ENODEV;
lbc = fsl_lbc_ctrl_dev->regs; for (i = 0; i < ARRAY_SIZE(lbc->bank); i++) {
u32 br = in_be32(&lbc->bank[i].br);
u32 or = in_be32(&lbc->bank[i].or);
if (br & BR_V && (br & or & BR_BA) == fsl_lbc_addr(addr_base)) return i;
}
return -ENOENT;
}
EXPORT_SYMBOL(fsl_lbc_find);
/** * fsl_upm_find - find pre-programmed UPM via base address * @addr_base: base address of the memory bank controlled by the UPM * @upm: pointer to the allocated fsl_upm structure * * This function fills fsl_upm structure so you can use it with the rest of * UPM API. On success this function returns 0, otherwise it returns * appropriate errno value.
*/ int fsl_upm_find(phys_addr_t addr_base, struct fsl_upm *upm)
{ int bank;
u32 br; struct fsl_lbc_regs __iomem *lbc;
bank = fsl_lbc_find(addr_base); if (bank < 0) return bank;
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) return -ENODEV;
switch (br & BR_MSEL) { case BR_MS_UPMA:
upm->mxmr = &lbc->mamr; break; case BR_MS_UPMB:
upm->mxmr = &lbc->mbmr; break; case BR_MS_UPMC:
upm->mxmr = &lbc->mcmr; break; default: return -EINVAL;
}
switch (br & BR_PS) { case BR_PS_8:
upm->width = 8; break; case BR_PS_16:
upm->width = 16; break; case BR_PS_32:
upm->width = 32; break; default: return -EINVAL;
}
return 0;
}
EXPORT_SYMBOL(fsl_upm_find);
/** * fsl_upm_run_pattern - actually run an UPM pattern * @upm: pointer to the fsl_upm structure obtained via fsl_upm_find * @io_base: remapped pointer to where memory access should happen * @mar: MAR register content during pattern execution * * This function triggers dummy write to the memory specified by the io_base, * thus UPM pattern actually executed. Note that mar usage depends on the * pre-programmed AMX bits in the UPM RAM.
*/ int fsl_upm_run_pattern(struct fsl_upm *upm, void __iomem *io_base, u32 mar)
{ int ret = 0; unsignedlong flags;
if (!fsl_lbc_ctrl_dev || !fsl_lbc_ctrl_dev->regs) return -ENODEV;
spin_lock_irqsave(&fsl_lbc_lock, flags);
out_be32(&fsl_lbc_ctrl_dev->regs->mar, mar);
switch (upm->width) { case 8:
out_8(io_base, 0x0); break; case 16:
out_be16(io_base, 0x0); break; case 32:
out_be32(io_base, 0x0); break; default:
ret = -EINVAL; break;
}
/* Set the monitor timeout value to the maximum for erratum A001 */ if (of_device_is_compatible(node, "fsl,elbc"))
clrsetbits_be32(&lbc->lbcr, LBCR_BMT, LBCR_BMTPS);
return 0;
}
/* * NOTE: This interrupt is used to report localbus events of various kinds, * such as transaction errors on the chipselects.
*/
/* * fsl_lbc_ctrl_probe * * called by device layer when it finds a device matching * one our driver can handled. This code allocates all of * the resources needed for the controller only. The * resources for the NAND banks themselves are allocated * in the chip probe function.
*/
staticint fsl_lbc_ctrl_probe(struct platform_device *dev)
{ int ret;
if (!dev->dev.of_node) {
dev_err(&dev->dev, "Device OF-Node is NULL"); return -EFAULT;
}
fsl_lbc_ctrl_dev = kzalloc(sizeof(*fsl_lbc_ctrl_dev), GFP_KERNEL); if (!fsl_lbc_ctrl_dev) return -ENOMEM;
fsl_lbc_ctrl_dev->regs = of_iomap(dev->dev.of_node, 0); if (!fsl_lbc_ctrl_dev->regs) {
dev_err(&dev->dev, "failed to get memory region\n");
ret = -ENODEV; goto err;
}
fsl_lbc_ctrl_dev->irq[0] = irq_of_parse_and_map(dev->dev.of_node, 0); if (!fsl_lbc_ctrl_dev->irq[0]) {
dev_err(&dev->dev, "failed to get irq resource\n");
ret = -ENODEV; goto err;
}
fsl_lbc_ctrl_dev->dev = &dev->dev;
ret = fsl_lbc_ctrl_init(fsl_lbc_ctrl_dev, dev->dev.of_node); if (ret < 0) goto err;
ret = request_irq(fsl_lbc_ctrl_dev->irq[0], fsl_lbc_ctrl_irq, 0, "fsl-lbc", fsl_lbc_ctrl_dev); if (ret != 0) {
dev_err(&dev->dev, "failed to install irq (%d)\n",
fsl_lbc_ctrl_dev->irq[0]);
ret = fsl_lbc_ctrl_dev->irq[0]; goto err;
}
fsl_lbc_ctrl_dev->irq[1] = irq_of_parse_and_map(dev->dev.of_node, 1); if (fsl_lbc_ctrl_dev->irq[1]) {
ret = request_irq(fsl_lbc_ctrl_dev->irq[1], fsl_lbc_ctrl_irq,
IRQF_SHARED, "fsl-lbc-err", fsl_lbc_ctrl_dev); if (ret) {
dev_err(&dev->dev, "failed to install irq (%d)\n",
fsl_lbc_ctrl_dev->irq[1]);
ret = fsl_lbc_ctrl_dev->irq[1]; goto err1;
}
}
/* Enable interrupts for any detected events */
out_be32(&fsl_lbc_ctrl_dev->regs->lteir, LTEIR_ENABLE);
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.