|
@@ -58,6 +58,19 @@
|
|
|
#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
|
|
|
+
|
|
|
#define __fsl_read_rio_config(x, addr, err, op) \
|
|
|
__asm__ __volatile__( \
|
|
|
"1: "op" %1,0(%2)\n" \
|
|
@@ -266,6 +279,89 @@ fsl_rio_config_write(struct rio_mport *mport, int index, u16 destid,
|
|
|
return 0;
|
|
|
}
|
|
|
|
|
|
+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);
|
|
|
+}
|
|
|
+
|
|
|
+int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart,
|
|
|
+ u64 rstart, u32 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)
|
|
|
+ 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;
|
|
|
+}
|
|
|
+
|
|
|
+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 */
|
|
@@ -389,6 +485,8 @@ int fsl_rio_setup(struct platform_device *dev)
|
|
|
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) {
|
|
@@ -602,6 +700,11 @@ int fsl_rio_setup(struct platform_device *dev)
|
|
|
RIO_ATMU_REGS_PORT2_OFFSET));
|
|
|
|
|
|
priv->maint_atmu_regs = priv->atmu_regs + 1;
|
|
|
+ priv->inb_atmu_regs = (struct rio_inb_atmu_regs __iomem *)
|
|
|
+ (priv->regs_win +
|
|
|
+ ((i == 0) ? RIO_INB_ATMU_REGS_PORT1_OFFSET :
|
|
|
+ RIO_INB_ATMU_REGS_PORT2_OFFSET));
|
|
|
+
|
|
|
|
|
|
/* Set to receive any dist ID for serial RapidIO controller. */
|
|
|
if (port->phy_type == RIO_PHY_SERIAL)
|
|
@@ -620,6 +723,7 @@ int fsl_rio_setup(struct platform_device *dev)
|
|
|
rio_law_start = range_start;
|
|
|
|
|
|
fsl_rio_setup_rmu(port, rmu_np[i]);
|
|
|
+ fsl_rio_inbound_mem_init(priv);
|
|
|
|
|
|
dbell->mport[i] = port;
|
|
|
|