/* * convert_ifc_address - convert the base address * @addr_base: base address of the memory bank
*/ unsignedint convert_ifc_address(phys_addr_t addr_base)
{ return addr_base & CSPR_BA;
}
EXPORT_SYMBOL(convert_ifc_address);
/* * fsl_ifc_find - find IFC bank * @addr_base: base address of the memory bank * * This function walks IFC banks comparing "Base address" field of the CSPR * 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_ifc_find(phys_addr_t addr_base)
{ int i = 0;
if (!fsl_ifc_ctrl_dev || !fsl_ifc_ctrl_dev->gregs) return -ENODEV;
for (i = 0; i < fsl_ifc_ctrl_dev->banks; i++) {
u32 cspr = ifc_in32(&fsl_ifc_ctrl_dev->gregs->cspr_cs[i].cspr);
/* * Clear all the common status and event registers
*/ if (ifc_in32(&ifc->cm_evter_stat) & IFC_CM_EVTER_STAT_CSER)
ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
/* enable all error and events */
ifc_out32(IFC_CM_EVTER_EN_CSEREN, &ifc->cm_evter_en);
/* enable all error and event interrupts */
ifc_out32(IFC_CM_EVTER_INTR_EN_CSERIREN, &ifc->cm_evter_intr_en);
ifc_out32(0x0, &ifc->cm_erattr0);
ifc_out32(0x0, &ifc->cm_erattr1);
/* * NAND events are split between an operational interrupt which only * receives OPC, and an error interrupt that receives everything else, * including non-NAND errors. Whichever interrupt gets to it first * records the status and wakes the wait queue.
*/ static DEFINE_SPINLOCK(nand_irq_lock);
/* * NOTE: This interrupt is used to report ifc events of various kinds, * such as transaction errors on the chipselects.
*/ static irqreturn_t fsl_ifc_ctrl_irq(int irqno, void *data)
{ struct fsl_ifc_ctrl *ctrl = data; struct fsl_ifc_global __iomem *ifc = ctrl->gregs;
u32 err_axiid, err_srcid, status, cs_err, err_addr;
irqreturn_t ret = IRQ_NONE;
/* read for chip select error */
cs_err = ifc_in32(&ifc->cm_evter_stat); if (cs_err) {
dev_err(ctrl->dev, "transaction sent to IFC is not mapped to any memory bank 0x%08X\n",
cs_err); /* clear the chip select error */
ifc_out32(IFC_CM_EVTER_STAT_CSER, &ifc->cm_evter_stat);
/* read error attribute registers print the error information */
status = ifc_in32(&ifc->cm_erattr0);
err_addr = ifc_in32(&ifc->cm_erattr1);
err_axiid = (status & IFC_CM_ERATTR0_ERAID) >>
IFC_CM_ERATTR0_ERAID_SHIFT;
dev_err(ctrl->dev, "AXI ID of the error transaction 0x%08X\n",
err_axiid);
err_srcid = (status & IFC_CM_ERATTR0_ESRCID) >>
IFC_CM_ERATTR0_ESRCID_SHIFT;
dev_err(ctrl->dev, "SRC ID of the error transaction 0x%08X\n",
err_srcid);
dev_err(ctrl->dev, "Transaction Address corresponding to error ERADDR 0x%08X\n",
err_addr);
ret = IRQ_HANDLED;
}
if (check_nand_stat(ctrl))
ret = IRQ_HANDLED;
return ret;
}
/* * fsl_ifc_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_ifc_ctrl_probe(struct platform_device *dev)
{ int ret = 0; int version, banks; void __iomem *addr;
fsl_ifc_ctrl_dev = devm_kzalloc(&dev->dev, sizeof(*fsl_ifc_ctrl_dev),
GFP_KERNEL); if (!fsl_ifc_ctrl_dev) return -ENOMEM;
dev_set_drvdata(&dev->dev, fsl_ifc_ctrl_dev);
/* IOMAP the entire IFC region */
fsl_ifc_ctrl_dev->gregs = of_iomap(dev->dev.of_node, 0); if (!fsl_ifc_ctrl_dev->gregs) {
dev_err(&dev->dev, "failed to get memory region\n"); return -ENODEV;
}
if (of_property_read_bool(dev->dev.of_node, "little-endian")) {
fsl_ifc_ctrl_dev->little_endian = true;
dev_dbg(&dev->dev, "IFC REGISTERS are LITTLE endian\n");
} else {
fsl_ifc_ctrl_dev->little_endian = false;
dev_dbg(&dev->dev, "IFC REGISTERS are BIG endian\n");
}
version = ifc_in32(&fsl_ifc_ctrl_dev->gregs->ifc_rev) &
FSL_IFC_VERSION_MASK;
/* get the Controller level irq */
fsl_ifc_ctrl_dev->irq = irq_of_parse_and_map(dev->dev.of_node, 0); if (fsl_ifc_ctrl_dev->irq == 0) {
dev_err(&dev->dev, "failed to get irq resource for IFC\n");
ret = -ENODEV; goto err;
}
/* get the nand machine irq */
fsl_ifc_ctrl_dev->nand_irq =
irq_of_parse_and_map(dev->dev.of_node, 1);
fsl_ifc_ctrl_dev->dev = &dev->dev;
ret = fsl_ifc_ctrl_init(fsl_ifc_ctrl_dev); if (ret < 0) goto err_unmap_nandirq;
ret = request_irq(fsl_ifc_ctrl_dev->irq, fsl_ifc_ctrl_irq, IRQF_SHARED, "fsl-ifc", fsl_ifc_ctrl_dev); if (ret != 0) {
dev_err(&dev->dev, "failed to install irq (%d)\n",
fsl_ifc_ctrl_dev->irq); goto err_unmap_nandirq;
}
if (fsl_ifc_ctrl_dev->nand_irq) {
ret = request_irq(fsl_ifc_ctrl_dev->nand_irq, fsl_ifc_nand_irq,
0, "fsl-ifc-nand", fsl_ifc_ctrl_dev); if (ret != 0) {
dev_err(&dev->dev, "failed to install irq (%d)\n",
fsl_ifc_ctrl_dev->nand_irq); goto err_free_irq;
}
}
/* legacy dts may still use "simple-bus" compatible */
ret = of_platform_default_populate(dev->dev.of_node, NULL, &dev->dev); if (ret) goto err_free_nandirq;
¤ 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.0.29Bemerkung:
(vorverarbeitet)
¤
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.