// SPDX-License-Identifier: GPL-2.0-or-later/* * Freescale MPC85xx/MPC86xx RapidIO support * * Copyright 2009 Sysgo AG * Thomas Moll <thomas.moll@sysgo.com> * - fixed maintenance access routines, check for aligned access * * Copyright 2009 Integrated Device Technology, Inc. * Alex Bounine <alexandre.bounine@idt.com> * - Added Port-Write message handling * - Added Machine Check exception handling * * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc. * Zhang Wei <wei.zhang@freescale.com> * * Copyright 2005 MontaVista Software, Inc. * Matt Porter <mporter@kernel.crashing.org> */ #include <linux/init.h>#include <linux/extable.h>#include <linux/types.h>#include <linux/dma-mapping.h>#include <linux/interrupt.h>#include <linux/of.h>#include <linux/of_address.h>#include <linux/of_irq.h>#include <linux/platform_device.h>#include <linux/delay.h>#include <linux/slab.h> #include <linux/io.h>#include <linux/uaccess.h>#include <asm/machdep.h>#include <asm/rio.h> #include "fsl_rio.h" #undef DEBUG_PW /* Port-Write debugging */ #define RIO_PORT1_EDCSR 0x0640#define RIO_PORT2_EDCSR 0x0680#define RIO_PORT1_IECSR 0x10130#define RIO_PORT2_IECSR 0x101B0 #define RIO_GCCSR 0x13c#define RIO_ESCSR 0x158#define ESCSR_CLEAR 0x07120204#define RIO_PORT2_ESCSR 0x178#define RIO_CCSR 0x15c#define RIO_LTLEDCSR_IER 0x80000000#define RIO_LTLEDCSR_PRT 0x01000000#define IECSR_CLEAR 0x80000000#define RIO_ISR_AACR 0x10120#define RIO_ISR_AACR_AA 0x1 /* Accept All ID */ #define RIWTAR_TRAD_VAL_SHIFT 12#define RIWTAR_TRAD_MASK 0x00FFFFFF#define RIWBAR_BADD_VAL_SHIFT 12#define RIWBAR_BADD_MASK 0x003FFFFF#define RIWAR_ENABLE 0x80000000#define RIWAR_TGINT_LOCAL 0x00F00000#define RIWAR_RDTYP_NO_SNOOP 0x00040000#define RIWAR_RDTYP_SNOOP 0x00050000#define RIWAR_WRTYP_NO_SNOOP 0x00004000#define RIWAR_WRTYP_SNOOP 0x00005000#define RIWAR_WRTYP_ALLOC 0x00006000#define RIWAR_SIZE_MASK 0x0000003F static DEFINE_SPINLOCK(fsl_rio_config_lock); #define ___fsl_read_rio_config(x, addr, err, op, barrier) \ __asm__ __volatile__( \ "1: "op" %1,0(%2)\n" \ " "barrier"\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: li %1,-1\n" \ " li %0,%3\n" \ " b 2b\n" \ ".previous\n" \ EX_TABLE(1b, 3b) \ : "=r" (err), "=r" (x) \ : "b" (addr), "i" (-EFAULT), "0" (err)) #ifdef CONFIG_BOOKE#define __fsl_read_rio_config(x, addr, err, op) \ ___fsl_read_rio_config(x, addr, err, op, "mbar")#else#define __fsl_read_rio_config(x, addr, err, op) \ ___fsl_read_rio_config(x, addr, err, op, "eieio")#endif void __iomem *rio_regs_win;void __iomem *rmu_regs_win;resource_size_t rio_law_start; struct fsl_rio_dbell *dbell;struct fsl_rio_pw *pw; #ifdef CONFIG_PPC_E500int fsl_rio_mcheck_exception(struct pt_regs *regs){ const struct exception_table_entry *entry; unsigned long reason; if (!rio_regs_win) return 0; reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) { /* Check if we are prepared to handle this fault */ entry = search_exception_tables(regs->nip); if (entry) { pr_debug("RIO: %s - MC Exception handled\n", __func__); out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); regs_set_recoverable(regs); regs_set_return_ip(regs, extable_fixup(entry)); return 1; } } return 0;}EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception);#endif /** * fsl_local_config_read - Generate a MPC85xx local config space read * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Value to be read into * * Generates a MPC85xx local configuration space read. Returns %0 on * success or %-EINVAL on failure. */static int fsl_local_config_read(struct rio_mport *mport, int index, u32 offset, int len, u32 *data){ struct rio_priv *priv = mport->priv; pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index, offset); *data = in_be32(priv->regs_win + offset); return 0;} /** * fsl_local_config_write - Generate a MPC85xx local config space write * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Value to be written * * Generates a MPC85xx local configuration space write. Returns %0 on * success or %-EINVAL on failure. */static int fsl_local_config_write(struct rio_mport *mport, int index, u32 offset, int len, u32 data){ struct rio_priv *priv = mport->priv; pr_debug ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n", index, offset, data); out_be32(priv->regs_win + offset, data); return 0;} /** * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @destid: Destination ID of transaction * @hopcount: Number of hops to target device * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @val: Location to be read into * * Generates a MPC85xx read maintenance transaction. Returns %0 on * success or %-EINVAL on failure. */static intfsl_rio_config_read(struct rio_mport *mport, int index, u16 destid, u8 hopcount, u32 offset, int len, u32 *val){ struct rio_priv *priv = mport->priv; unsigned long flags; u8 *data; u32 rval, err = 0; pr_debug ("fsl_rio_config_read:" " index %d destid %d hopcount %d offset %8.8x len %d\n", index, destid, hopcount, offset, len); /* 16MB maintenance window possible */ /* allow only aligned access to maintenance registers */ if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) return -EINVAL; spin_lock_irqsave(&fsl_rio_config_lock, flags); out_be32(&priv->maint_atmu_regs->rowtar, (destid << 22) | (hopcount << 12) | (offset >> 12)); out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); switch (len) { case 1: __fsl_read_rio_config(rval, data, err, "lbz"); break; case 2: __fsl_read_rio_config(rval, data, err, "lhz"); break; case 4: __fsl_read_rio_config(rval, data, err, "lwz"); break; default: spin_unlock_irqrestore(&fsl_rio_config_lock, flags); return -EINVAL; } if (err) { pr_debug("RIO: cfg_read error %d for %x:%x:%x\n", err, destid, hopcount, offset); } spin_unlock_irqrestore(&fsl_rio_config_lock, flags); *val = rval; return err;} /** * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @destid: Destination ID of transaction * @hopcount: Number of hops to target device * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @val: Value to be written * * Generates an MPC85xx write maintenance transaction. Returns %0 on * success or %-EINVAL on failure. */static intfsl_rio_config_write(struct rio_mport *mport, int index, u16 destid, u8 hopcount, u32 offset, int len, u32 val){ struct rio_priv *priv = mport->priv; unsigned long flags; u8 *data; int ret = 0; pr_debug ("fsl_rio_config_write:" " index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", index, destid, hopcount, offset, len, val); /* 16MB maintenance windows possible */ /* allow only aligned access to maintenance registers */ if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) return -EINVAL; spin_lock_irqsave(&fsl_rio_config_lock, flags); out_be32(&priv->maint_atmu_regs->rowtar, (destid << 22) | (hopcount << 12) | (offset >> 12)); out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); switch (len) { case 1: out_8((u8 *) data, val); break; case 2: out_be16((u16 *) data, val); break; case 4: out_be32((u32 *) data, val); break; default: ret = -EINVAL; } spin_unlock_irqrestore(&fsl_rio_config_lock, flags); return ret;} static void fsl_rio_inbound_mem_init(struct rio_priv *priv){ int i; /* close inbound windows */ for (i = 0; i < RIO_INB_ATMU_COUNT; i++) out_be32(&priv->inb_atmu_regs[i].riwar, 0);} static int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, u64 rstart, u64 size, u32 flags){ struct rio_priv *priv = mport->priv; u32 base_size; unsigned int base_size_log; u64 win_start, win_end; u32 riwar; int i; if ((size & (size - 1)) != 0 || size > 0x400000000ULL) return -EINVAL; base_size_log = ilog2(size); base_size = 1 << base_size_log; /* check if addresses are aligned with the window size */ if (lstart & (base_size - 1)) return -EINVAL; if (rstart & (base_size - 1)) return -EINVAL; /* check for conflicting ranges */ for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { riwar = in_be32(&priv->inb_atmu_regs[i].riwar); if ((riwar & RIWAR_ENABLE) == 0) continue; win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK)) << RIWBAR_BADD_VAL_SHIFT; win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1); if (rstart < win_end && (rstart + size) > win_start) return -EINVAL; } /* find unused atmu */ for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { riwar = in_be32(&priv->inb_atmu_regs[i].riwar); if ((riwar & RIWAR_ENABLE) == 0) break; } if (i >= RIO_INB_ATMU_COUNT) return -ENOMEM; out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT); out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT); out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL | RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1)); return 0;} static void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart){ u32 win_start_shift, base_start_shift; struct rio_priv *priv = mport->priv; u32 riwar, riwtar; int i; /* skip default window */ base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT; for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { riwar = in_be32(&priv->inb_atmu_regs[i].riwar); if ((riwar & RIWAR_ENABLE) == 0) continue; riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar); win_start_shift = riwtar & RIWTAR_TRAD_MASK; if (win_start_shift == base_start_shift) { out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE); return; } }} void fsl_rio_port_error_handler(int offset){ /*XXX: Error recovery is not implemented, we just clear errors */ out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); if (offset == 0) { out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0); out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR); out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR); } else { out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0); out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR); out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR); }}static inline void fsl_rio_info(struct device *dev, u32 ccsr){ const char *str; if (ccsr & 1) { /* Serial phy */ switch (ccsr >> 30) { case 0: str = "1"; break; case 1: str = "4"; break; default: str = "Unknown"; break; } dev_info(dev, "Hardware port width: %s\n", str); switch ((ccsr >> 27) & 7) { case 0: str = "Single-lane 0"; break; case 1: str = "Single-lane 2"; break; case 2: str = "Four-lane"; break; default: str = "Unknown"; break; } dev_info(dev, "Training connection status: %s\n", str); } else { /* Parallel phy */ if (!(ccsr & 0x80000000)) dev_info(dev, "Output port operating in 8-bit mode\n"); if (!(ccsr & 0x08000000)) dev_info(dev, "Input port operating in 8-bit mode\n"); }} /** * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface * @dev: platform_device pointer * * Initializes MPC85xx RapidIO hardware interface, configures * master port with system-specific info, and registers the * master port with the RapidIO subsystem. */static int fsl_rio_setup(struct platform_device *dev){ struct rio_ops *ops; struct rio_mport *port; struct rio_priv *priv; int rc = 0; const u32 *port_index; u32 active_ports = 0; struct device_node *np, *rmu_node; u32 ccsr; u64 range_start; u32 i; static int tmp; struct device_node *rmu_np[MAX_MSG_UNIT_NUM] = {NULL}; if (!dev->dev.of_node) { dev_err(&dev->dev, "Device OF-Node is NULL"); return -ENODEV; } rio_regs_win = of_iomap(dev->dev.of_node, 0); if (!rio_regs_win) { dev_err(&dev->dev, "Unable to map rio register window\n"); rc = -ENOMEM; goto err_rio_regs; } ops = kzalloc_obj(struct rio_ops); if (!ops) { rc = -ENOMEM; goto err_ops; } ops->lcread = fsl_local_config_read; ops->lcwrite = fsl_local_config_write; ops->cread = fsl_rio_config_read; ops->cwrite = fsl_rio_config_write; ops->dsend = fsl_rio_doorbell_send; ops->pwenable = fsl_rio_pw_enable; ops->open_outb_mbox = fsl_open_outb_mbox; ops->open_inb_mbox = fsl_open_inb_mbox; ops->close_outb_mbox = fsl_close_outb_mbox; ops->close_inb_mbox = fsl_close_inb_mbox; ops->add_outb_message = fsl_add_outb_message; ops->add_inb_buffer = fsl_add_inb_buffer; ops->get_inb_message = fsl_get_inb_message; ops->map_inb = fsl_map_inb_mem; ops->unmap_inb = fsl_unmap_inb_mem; rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0); if (!rmu_node) { dev_err(&dev->dev, "No valid fsl,srio-rmu-handle property\n"); rc = -ENOENT; goto err_rmu; } rmu_regs_win = of_iomap(rmu_node, 0);Lines 1–500 of 763. Load more
// SPDX-License-Identifier: GPL-2.0-or-later /* * Freescale MPC85xx/MPC86xx RapidIO support * * Copyright 2009 Sysgo AG * Thomas Moll <thomas.moll@sysgo.com> * - fixed maintenance access routines, check for aligned access * * Copyright 2009 Integrated Device Technology, Inc. * Alex Bounine <alexandre.bounine@idt.com> * - Added Port-Write message handling * - Added Machine Check exception handling * * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc. * Zhang Wei <wei.zhang@freescale.com> * * Copyright 2005 MontaVista Software, Inc. * Matt Porter <mporter@kernel.crashing.org> */ #include <linux/init.h> #include <linux/extable.h> #include <linux/types.h> #include <linux/dma-mapping.h> #include <linux/interrupt.h> #include <linux/of.h> #include <linux/of_address.h> #include <linux/of_irq.h> #include <linux/platform_device.h> #include <linux/delay.h> #include <linux/slab.h> #include <linux/io.h> #include <linux/uaccess.h> #include <asm/machdep.h> #include <asm/rio.h> #include "fsl_rio.h" #undef DEBUG_PW /* Port-Write debugging */ #define RIO_PORT1_EDCSR 0x0640 #define RIO_PORT2_EDCSR 0x0680 #define RIO_PORT1_IECSR 0x10130 #define RIO_PORT2_IECSR 0x101B0 #define RIO_GCCSR 0x13c #define RIO_ESCSR 0x158 #define ESCSR_CLEAR 0x07120204 #define RIO_PORT2_ESCSR 0x178 #define RIO_CCSR 0x15c #define RIO_LTLEDCSR_IER 0x80000000 #define RIO_LTLEDCSR_PRT 0x01000000 #define IECSR_CLEAR 0x80000000 #define RIO_ISR_AACR 0x10120 #define RIO_ISR_AACR_AA 0x1 /* Accept All ID */ #define RIWTAR_TRAD_VAL_SHIFT 12 #define RIWTAR_TRAD_MASK 0x00FFFFFF #define RIWBAR_BADD_VAL_SHIFT 12 #define RIWBAR_BADD_MASK 0x003FFFFF #define RIWAR_ENABLE 0x80000000 #define RIWAR_TGINT_LOCAL 0x00F00000 #define RIWAR_RDTYP_NO_SNOOP 0x00040000 #define RIWAR_RDTYP_SNOOP 0x00050000 #define RIWAR_WRTYP_NO_SNOOP 0x00004000 #define RIWAR_WRTYP_SNOOP 0x00005000 #define RIWAR_WRTYP_ALLOC 0x00006000 #define RIWAR_SIZE_MASK 0x0000003F static DEFINE_SPINLOCK(fsl_rio_config_lock); #define ___fsl_read_rio_config(x, addr, err, op, barrier) \ __asm__ __volatile__( \ "1: "op" %1,0(%2)\n" \ " "barrier"\n" \ "2:\n" \ ".section .fixup,\"ax\"\n" \ "3: li %1,-1\n" \ " li %0,%3\n" \ " b 2b\n" \ ".previous\n" \ EX_TABLE(1b, 3b) \ : "=r" (err), "=r" (x) \ : "b" (addr), "i" (-EFAULT), "0" (err)) #ifdef CONFIG_BOOKE #define __fsl_read_rio_config(x, addr, err, op) \ ___fsl_read_rio_config(x, addr, err, op, "mbar") #else #define __fsl_read_rio_config(x, addr, err, op) \ ___fsl_read_rio_config(x, addr, err, op, "eieio") #endif void __iomem *rio_regs_win; void __iomem *rmu_regs_win; resource_size_t rio_law_start; struct fsl_rio_dbell *dbell; struct fsl_rio_pw *pw; #ifdef CONFIG_PPC_E500 int fsl_rio_mcheck_exception(struct pt_regs *regs) { const struct exception_table_entry *entry; unsigned long reason; if (!rio_regs_win) return 0; reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) { /* Check if we are prepared to handle this fault */ entry = search_exception_tables(regs->nip); if (entry) { pr_debug("RIO: %s - MC Exception handled\n", __func__); out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); regs_set_recoverable(regs); regs_set_return_ip(regs, extable_fixup(entry)); return 1; } } return 0; } EXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception); #endif /** * fsl_local_config_read - Generate a MPC85xx local config space read * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Value to be read into * * Generates a MPC85xx local configuration space read. Returns %0 on * success or %-EINVAL on failure. */ static int fsl_local_config_read(struct rio_mport *mport, int index, u32 offset, int len, u32 *data) { struct rio_priv *priv = mport->priv; pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index, offset); *data = in_be32(priv->regs_win + offset); return 0; } /** * fsl_local_config_write - Generate a MPC85xx local config space write * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @data: Value to be written * * Generates a MPC85xx local configuration space write. Returns %0 on * success or %-EINVAL on failure. */ static int fsl_local_config_write(struct rio_mport *mport, int index, u32 offset, int len, u32 data) { struct rio_priv *priv = mport->priv; pr_debug ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n", index, offset, data); out_be32(priv->regs_win + offset, data); return 0; } /** * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @destid: Destination ID of transaction * @hopcount: Number of hops to target device * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @val: Location to be read into * * Generates a MPC85xx read maintenance transaction. Returns %0 on * success or %-EINVAL on failure. */ static int fsl_rio_config_read(struct rio_mport *mport, int index, u16 destid, u8 hopcount, u32 offset, int len, u32 *val) { struct rio_priv *priv = mport->priv; unsigned long flags; u8 *data; u32 rval, err = 0; pr_debug ("fsl_rio_config_read:" " index %d destid %d hopcount %d offset %8.8x len %d\n", index, destid, hopcount, offset, len); /* 16MB maintenance window possible */ /* allow only aligned access to maintenance registers */ if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) return -EINVAL; spin_lock_irqsave(&fsl_rio_config_lock, flags); out_be32(&priv->maint_atmu_regs->rowtar, (destid << 22) | (hopcount << 12) | (offset >> 12)); out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); switch (len) { case 1: __fsl_read_rio_config(rval, data, err, "lbz"); break; case 2: __fsl_read_rio_config(rval, data, err, "lhz"); break; case 4: __fsl_read_rio_config(rval, data, err, "lwz"); break; default: spin_unlock_irqrestore(&fsl_rio_config_lock, flags); return -EINVAL; } if (err) { pr_debug("RIO: cfg_read error %d for %x:%x:%x\n", err, destid, hopcount, offset); } spin_unlock_irqrestore(&fsl_rio_config_lock, flags); *val = rval; return err; } /** * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction * @mport: RapidIO master port info * @index: ID of RapdiIO interface * @destid: Destination ID of transaction * @hopcount: Number of hops to target device * @offset: Offset into configuration space * @len: Length (in bytes) of the maintenance transaction * @val: Value to be written * * Generates an MPC85xx write maintenance transaction. Returns %0 on * success or %-EINVAL on failure. */ static int fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid, u8 hopcount, u32 offset, int len, u32 val) { struct rio_priv *priv = mport->priv; unsigned long flags; u8 *data; int ret = 0; pr_debug ("fsl_rio_config_write:" " index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", index, destid, hopcount, offset, len, val); /* 16MB maintenance windows possible */ /* allow only aligned access to maintenance registers */ if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) return -EINVAL; spin_lock_irqsave(&fsl_rio_config_lock, flags); out_be32(&priv->maint_atmu_regs->rowtar, (destid << 22) | (hopcount << 12) | (offset >> 12)); out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); switch (len) { case 1: out_8((u8 *) data, val); break; case 2: out_be16((u16 *) data, val); break; case 4: out_be32((u32 *) data, val); break; default: ret = -EINVAL; } spin_unlock_irqrestore(&fsl_rio_config_lock, flags); return ret; } static void fsl_rio_inbound_mem_init(struct rio_priv *priv) { int i; /* close inbound windows */ for (i = 0; i < RIO_INB_ATMU_COUNT; i++) out_be32(&priv->inb_atmu_regs[i].riwar, 0); } static int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, u64 rstart, u64 size, u32 flags) { struct rio_priv *priv = mport->priv; u32 base_size; unsigned int base_size_log; u64 win_start, win_end; u32 riwar; int i; if ((size & (size - 1)) != 0 || size > 0x400000000ULL) return -EINVAL; base_size_log = ilog2(size); base_size = 1 << base_size_log; /* check if addresses are aligned with the window size */ if (lstart & (base_size - 1)) return -EINVAL; if (rstart & (base_size - 1)) return -EINVAL; /* check for conflicting ranges */ for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { riwar = in_be32(&priv->inb_atmu_regs[i].riwar); if ((riwar & RIWAR_ENABLE) == 0) continue; win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK)) << RIWBAR_BADD_VAL_SHIFT; win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1); if (rstart < win_end && (rstart + size) > win_start) return -EINVAL; } /* find unused atmu */ for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { riwar = in_be32(&priv->inb_atmu_regs[i].riwar); if ((riwar & RIWAR_ENABLE) == 0) break; } if (i >= RIO_INB_ATMU_COUNT) return -ENOMEM; out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT); out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT); out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL | RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1)); return 0; } static void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart) { u32 win_start_shift, base_start_shift; struct rio_priv *priv = mport->priv; u32 riwar, riwtar; int i; /* skip default window */ base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT; for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { riwar = in_be32(&priv->inb_atmu_regs[i].riwar); if ((riwar & RIWAR_ENABLE) == 0) continue; riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar); win_start_shift = riwtar & RIWTAR_TRAD_MASK; if (win_start_shift == base_start_shift) { out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE); return; } } } void fsl_rio_port_error_handler(int offset) { /*XXX: Error recovery is not implemented, we just clear errors */ out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); if (offset == 0) { out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0); out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR); out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR); } else { out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0); out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR); out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR); } } static inline void fsl_rio_info(struct device *dev, u32 ccsr) { const char *str; if (ccsr & 1) { /* Serial phy */ switch (ccsr >> 30) { case 0: str = "1"; break; case 1: str = "4"; break; default: str = "Unknown"; break; } dev_info(dev, "Hardware port width: %s\n", str); switch ((ccsr >> 27) & 7) { case 0: str = "Single-lane 0"; break; case 1: str = "Single-lane 2"; break; case 2: str = "Four-lane"; break; default: str = "Unknown"; break; } dev_info(dev, "Training connection status: %s\n", str); } else { /* Parallel phy */ if (!(ccsr & 0x80000000)) dev_info(dev, "Output port operating in 8-bit mode\n"); if (!(ccsr & 0x08000000)) dev_info(dev, "Input port operating in 8-bit mode\n"); } } /** * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface * @dev: platform_device pointer * * Initializes MPC85xx RapidIO hardware interface, configures * master port with system-specific info, and registers the * master port with the RapidIO subsystem. */ static int fsl_rio_setup(struct platform_device *dev) { struct rio_ops *ops; struct rio_mport *port; struct rio_priv *priv; int rc = 0; const u32 *port_index; u32 active_ports = 0; struct device_node *np, *rmu_node; u32 ccsr; u64 range_start; u32 i; static int tmp; struct device_node *rmu_np[MAX_MSG_UNIT_NUM] = {NULL}; if (!dev->dev.of_node) { dev_err(&dev->dev, "Device OF-Node is NULL"); return -ENODEV; } rio_regs_win = of_iomap(dev->dev.of_node, 0); if (!rio_regs_win) { dev_err(&dev->dev, "Unable to map rio register window\n"); rc = -ENOMEM; goto err_rio_regs; } ops = kzalloc_obj(struct rio_ops); if (!ops) { rc = -ENOMEM; goto err_ops; } ops->lcread = fsl_local_config_read; ops->lcwrite = fsl_local_config_write; ops->cread = fsl_rio_config_read; ops->cwrite = fsl_rio_config_write; ops->dsend = fsl_rio_doorbell_send; ops->pwenable = fsl_rio_pw_enable; ops->open_outb_mbox = fsl_open_outb_mbox; ops->open_inb_mbox = fsl_open_inb_mbox; ops->close_outb_mbox = fsl_close_outb_mbox; ops->close_inb_mbox = fsl_close_inb_mbox; ops->add_outb_message = fsl_add_outb_message; ops->add_inb_buffer = fsl_add_inb_buffer; ops->get_inb_message = fsl_get_inb_message; ops->map_inb = fsl_map_inb_mem; ops->unmap_inb = fsl_unmap_inb_mem; rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0); if (!rmu_node) { dev_err(&dev->dev, "No valid fsl,srio-rmu-handle property\n"); rc = -ENOENT; goto err_rmu; } rmu_regs_win = of_iomap(rmu_node, 0);