1217309Snwhitehorn// SPDX-License-Identifier: GPL-2.0-or-later 2220749Snwhitehorn/* 3217309Snwhitehorn * Freescale MPC85xx/MPC86xx RapidIO support 4217309Snwhitehorn * 5217309Snwhitehorn * Copyright 2009 Sysgo AG 6220749Snwhitehorn * Thomas Moll <thomas.moll@sysgo.com> 7217309Snwhitehorn * - fixed maintenance access routines, check for aligned access 8217309Snwhitehorn * 9217309Snwhitehorn * Copyright 2009 Integrated Device Technology, Inc. 10217309Snwhitehorn * Alex Bounine <alexandre.bounine@idt.com> 11217309Snwhitehorn * - Added Port-Write message handling 12217309Snwhitehorn * - Added Machine Check exception handling 13217309Snwhitehorn * 14217309Snwhitehorn * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc. 15217309Snwhitehorn * Zhang Wei <wei.zhang@freescale.com> 16217309Snwhitehorn * 17217309Snwhitehorn * Copyright 2005 MontaVista Software, Inc. 18217309Snwhitehorn * Matt Porter <mporter@kernel.crashing.org> 19217309Snwhitehorn */ 20217309Snwhitehorn 21217309Snwhitehorn#include <linux/init.h> 22217309Snwhitehorn#include <linux/extable.h> 23217309Snwhitehorn#include <linux/types.h> 24217309Snwhitehorn#include <linux/dma-mapping.h> 25217309Snwhitehorn#include <linux/interrupt.h> 26217309Snwhitehorn#include <linux/of.h> 27217309Snwhitehorn#include <linux/of_address.h> 28217309Snwhitehorn#include <linux/of_irq.h> 29217309Snwhitehorn#include <linux/platform_device.h> 30217309Snwhitehorn#include <linux/delay.h> 31217309Snwhitehorn#include <linux/slab.h> 32217309Snwhitehorn 33217309Snwhitehorn#include <linux/io.h> 34217309Snwhitehorn#include <linux/uaccess.h> 35217309Snwhitehorn#include <asm/machdep.h> 36217309Snwhitehorn#include <asm/rio.h> 37217309Snwhitehorn 38217309Snwhitehorn#include "fsl_rio.h" 39217309Snwhitehorn 40217309Snwhitehorn#undef DEBUG_PW /* Port-Write debugging */ 41217309Snwhitehorn 42217309Snwhitehorn#define RIO_PORT1_EDCSR 0x0640 43217309Snwhitehorn#define RIO_PORT2_EDCSR 0x0680 44217309Snwhitehorn#define RIO_PORT1_IECSR 0x10130 45217309Snwhitehorn#define RIO_PORT2_IECSR 0x101B0 46217309Snwhitehorn 47217309Snwhitehorn#define RIO_GCCSR 0x13c 48217309Snwhitehorn#define RIO_ESCSR 0x158 49217309Snwhitehorn#define ESCSR_CLEAR 0x07120204 50217309Snwhitehorn#define RIO_PORT2_ESCSR 0x178 51217309Snwhitehorn#define RIO_CCSR 0x15c 52217309Snwhitehorn#define RIO_LTLEDCSR_IER 0x80000000 53217309Snwhitehorn#define RIO_LTLEDCSR_PRT 0x01000000 54217309Snwhitehorn#define IECSR_CLEAR 0x80000000 55217309Snwhitehorn#define RIO_ISR_AACR 0x10120 56217309Snwhitehorn#define RIO_ISR_AACR_AA 0x1 /* Accept All ID */ 57217309Snwhitehorn 58217309Snwhitehorn#define RIWTAR_TRAD_VAL_SHIFT 12 59217309Snwhitehorn#define RIWTAR_TRAD_MASK 0x00FFFFFF 60217309Snwhitehorn#define RIWBAR_BADD_VAL_SHIFT 12 61217309Snwhitehorn#define RIWBAR_BADD_MASK 0x003FFFFF 62217309Snwhitehorn#define RIWAR_ENABLE 0x80000000 63217309Snwhitehorn#define RIWAR_TGINT_LOCAL 0x00F00000 64217309Snwhitehorn#define RIWAR_RDTYP_NO_SNOOP 0x00040000 65217309Snwhitehorn#define RIWAR_RDTYP_SNOOP 0x00050000 66217309Snwhitehorn#define RIWAR_WRTYP_NO_SNOOP 0x00004000 67217309Snwhitehorn#define RIWAR_WRTYP_SNOOP 0x00005000 68217309Snwhitehorn#define RIWAR_WRTYP_ALLOC 0x00006000 69217309Snwhitehorn#define RIWAR_SIZE_MASK 0x0000003F 70217309Snwhitehorn 71217309Snwhitehornstatic DEFINE_SPINLOCK(fsl_rio_config_lock); 72217309Snwhitehorn 73217309Snwhitehorn#define ___fsl_read_rio_config(x, addr, err, op, barrier) \ 74217309Snwhitehorn __asm__ __volatile__( \ 75217309Snwhitehorn "1: "op" %1,0(%2)\n" \ 76217309Snwhitehorn " "barrier"\n" \ 77217309Snwhitehorn "2:\n" \ 78217309Snwhitehorn ".section .fixup,\"ax\"\n" \ 79217309Snwhitehorn "3: li %1,-1\n" \ 80217309Snwhitehorn " li %0,%3\n" \ 81217309Snwhitehorn " b 2b\n" \ 82217309Snwhitehorn ".previous\n" \ 83217309Snwhitehorn EX_TABLE(1b, 3b) \ 84217309Snwhitehorn : "=r" (err), "=r" (x) \ 85217309Snwhitehorn : "b" (addr), "i" (-EFAULT), "0" (err)) 86217309Snwhitehorn 87217309Snwhitehorn#ifdef CONFIG_BOOKE 88217309Snwhitehorn#define __fsl_read_rio_config(x, addr, err, op) \ 89217309Snwhitehorn ___fsl_read_rio_config(x, addr, err, op, "mbar") 90217309Snwhitehorn#else 91217309Snwhitehorn#define __fsl_read_rio_config(x, addr, err, op) \ 92217309Snwhitehorn ___fsl_read_rio_config(x, addr, err, op, "eieio") 93217309Snwhitehorn#endif 94217309Snwhitehorn 95217309Snwhitehornvoid __iomem *rio_regs_win; 96217309Snwhitehornvoid __iomem *rmu_regs_win; 97217309Snwhitehornresource_size_t rio_law_start; 98217309Snwhitehorn 99217309Snwhitehornstruct fsl_rio_dbell *dbell; 100217309Snwhitehornstruct fsl_rio_pw *pw; 101217309Snwhitehorn 102217309Snwhitehorn#ifdef CONFIG_PPC_E500 103217309Snwhitehornint fsl_rio_mcheck_exception(struct pt_regs *regs) 104217309Snwhitehorn{ 105217309Snwhitehorn const struct exception_table_entry *entry; 106217309Snwhitehorn unsigned long reason; 107217309Snwhitehorn 108217309Snwhitehorn if (!rio_regs_win) 109217309Snwhitehorn return 0; 110217309Snwhitehorn 111217309Snwhitehorn reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); 112217309Snwhitehorn if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) { 113217309Snwhitehorn /* Check if we are prepared to handle this fault */ 114217309Snwhitehorn entry = search_exception_tables(regs->nip); 115217309Snwhitehorn if (entry) { 116217309Snwhitehorn pr_debug("RIO: %s - MC Exception handled\n", 117217309Snwhitehorn __func__); 118217309Snwhitehorn out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 119217309Snwhitehorn 0); 120220749Snwhitehorn regs_set_recoverable(regs); 121217309Snwhitehorn regs_set_return_ip(regs, extable_fixup(entry)); 122217309Snwhitehorn return 1; 123217309Snwhitehorn } 124217309Snwhitehorn } 125217309Snwhitehorn 126217309Snwhitehorn return 0; 127217309Snwhitehorn} 128217309SnwhitehornEXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception); 129217309Snwhitehorn#endif 130217309Snwhitehorn 131217309Snwhitehorn/** 132217309Snwhitehorn * fsl_local_config_read - Generate a MPC85xx local config space read 133217309Snwhitehorn * @mport: RapidIO master port info 134217309Snwhitehorn * @index: ID of RapdiIO interface 135217309Snwhitehorn * @offset: Offset into configuration space 136217309Snwhitehorn * @len: Length (in bytes) of the maintenance transaction 137217309Snwhitehorn * @data: Value to be read into 138217309Snwhitehorn * 139217309Snwhitehorn * Generates a MPC85xx local configuration space read. Returns %0 on 140217309Snwhitehorn * success or %-EINVAL on failure. 141217309Snwhitehorn */ 142217309Snwhitehornstatic int fsl_local_config_read(struct rio_mport *mport, 143217309Snwhitehorn int index, u32 offset, int len, u32 *data) 144217309Snwhitehorn{ 145217309Snwhitehorn struct rio_priv *priv = mport->priv; 146217309Snwhitehorn pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index, 147217309Snwhitehorn offset); 148217309Snwhitehorn *data = in_be32(priv->regs_win + offset); 149217309Snwhitehorn 150217309Snwhitehorn return 0; 151217309Snwhitehorn} 152217309Snwhitehorn 153217309Snwhitehorn/** 154217309Snwhitehorn * fsl_local_config_write - Generate a MPC85xx local config space write 155217309Snwhitehorn * @mport: RapidIO master port info 156217309Snwhitehorn * @index: ID of RapdiIO interface 157217309Snwhitehorn * @offset: Offset into configuration space 158217309Snwhitehorn * @len: Length (in bytes) of the maintenance transaction 159217309Snwhitehorn * @data: Value to be written 160217309Snwhitehorn * 161217309Snwhitehorn * Generates a MPC85xx local configuration space write. Returns %0 on 162217309Snwhitehorn * success or %-EINVAL on failure. 163217309Snwhitehorn */ 164217309Snwhitehornstatic int fsl_local_config_write(struct rio_mport *mport, 165217309Snwhitehorn int index, u32 offset, int len, u32 data) 166217309Snwhitehorn{ 167217309Snwhitehorn struct rio_priv *priv = mport->priv; 168217309Snwhitehorn pr_debug 169217309Snwhitehorn ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n", 170217309Snwhitehorn index, offset, data); 171217309Snwhitehorn out_be32(priv->regs_win + offset, data); 172217309Snwhitehorn 173217309Snwhitehorn return 0; 174217309Snwhitehorn} 175217309Snwhitehorn 176217309Snwhitehorn/** 177217309Snwhitehorn * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction 178217309Snwhitehorn * @mport: RapidIO master port info 179217309Snwhitehorn * @index: ID of RapdiIO interface 180217309Snwhitehorn * @destid: Destination ID of transaction 181217309Snwhitehorn * @hopcount: Number of hops to target device 182217309Snwhitehorn * @offset: Offset into configuration space 183217309Snwhitehorn * @len: Length (in bytes) of the maintenance transaction 184217309Snwhitehorn * @val: Location to be read into 185217309Snwhitehorn * 186217309Snwhitehorn * Generates a MPC85xx read maintenance transaction. Returns %0 on 187217309Snwhitehorn * success or %-EINVAL on failure. 188217309Snwhitehorn */ 189217309Snwhitehornstatic int 190217309Snwhitehornfsl_rio_config_read(struct rio_mport *mport, int index, u16 destid, 191220749Snwhitehorn u8 hopcount, u32 offset, int len, u32 *val) 192217309Snwhitehorn{ 193217309Snwhitehorn struct rio_priv *priv = mport->priv; 194217309Snwhitehorn unsigned long flags; 195217309Snwhitehorn u8 *data; 196217309Snwhitehorn u32 rval, err = 0; 197217309Snwhitehorn 198217309Snwhitehorn pr_debug 199217309Snwhitehorn ("fsl_rio_config_read:" 200217309Snwhitehorn " index %d destid %d hopcount %d offset %8.8x len %d\n", 201217309Snwhitehorn index, destid, hopcount, offset, len); 202217309Snwhitehorn 203217309Snwhitehorn /* 16MB maintenance window possible */ 204217309Snwhitehorn /* allow only aligned access to maintenance registers */ 205217309Snwhitehorn if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) 206217309Snwhitehorn return -EINVAL; 207217309Snwhitehorn 208217309Snwhitehorn spin_lock_irqsave(&fsl_rio_config_lock, flags); 209217309Snwhitehorn 210217309Snwhitehorn out_be32(&priv->maint_atmu_regs->rowtar, 211217309Snwhitehorn (destid << 22) | (hopcount << 12) | (offset >> 12)); 212217309Snwhitehorn out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); 213217309Snwhitehorn 214217309Snwhitehorn data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); 215217309Snwhitehorn switch (len) { 216217309Snwhitehorn case 1: 217217309Snwhitehorn __fsl_read_rio_config(rval, data, err, "lbz"); 218217309Snwhitehorn break; 219217309Snwhitehorn case 2: 220217309Snwhitehorn __fsl_read_rio_config(rval, data, err, "lhz"); 221217309Snwhitehorn break; 222217309Snwhitehorn case 4: 223217309Snwhitehorn __fsl_read_rio_config(rval, data, err, "lwz"); 224217309Snwhitehorn break; 225217309Snwhitehorn default: 226217309Snwhitehorn spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 227217309Snwhitehorn return -EINVAL; 228217309Snwhitehorn } 229217309Snwhitehorn 230217309Snwhitehorn if (err) { 231217309Snwhitehorn pr_debug("RIO: cfg_read error %d for %x:%x:%x\n", 232217309Snwhitehorn err, destid, hopcount, offset); 233217309Snwhitehorn } 234217309Snwhitehorn 235217309Snwhitehorn spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 236217309Snwhitehorn *val = rval; 237217309Snwhitehorn 238217309Snwhitehorn return err; 239217309Snwhitehorn} 240217309Snwhitehorn 241217309Snwhitehorn/** 242217309Snwhitehorn * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction 243217309Snwhitehorn * @mport: RapidIO master port info 244217309Snwhitehorn * @index: ID of RapdiIO interface 245217309Snwhitehorn * @destid: Destination ID of transaction 246217309Snwhitehorn * @hopcount: Number of hops to target device 247217309Snwhitehorn * @offset: Offset into configuration space 248217309Snwhitehorn * @len: Length (in bytes) of the maintenance transaction 249217309Snwhitehorn * @val: Value to be written 250217309Snwhitehorn * 251217309Snwhitehorn * Generates an MPC85xx write maintenance transaction. Returns %0 on 252217309Snwhitehorn * success or %-EINVAL on failure. 253217309Snwhitehorn */ 254217309Snwhitehornstatic int 255217309Snwhitehornfsl_rio_config_write(struct rio_mport *mport, int index, u16 destid, 256217309Snwhitehorn u8 hopcount, u32 offset, int len, u32 val) 257217309Snwhitehorn{ 258217309Snwhitehorn struct rio_priv *priv = mport->priv; 259217309Snwhitehorn unsigned long flags; 260217309Snwhitehorn u8 *data; 261217309Snwhitehorn int ret = 0; 262217309Snwhitehorn 263217309Snwhitehorn pr_debug 264217309Snwhitehorn ("fsl_rio_config_write:" 265217309Snwhitehorn " index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", 266217309Snwhitehorn index, destid, hopcount, offset, len, val); 267217309Snwhitehorn 268217309Snwhitehorn /* 16MB maintenance windows possible */ 269217309Snwhitehorn /* allow only aligned access to maintenance registers */ 270217309Snwhitehorn if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) 271217309Snwhitehorn return -EINVAL; 272217309Snwhitehorn 273217309Snwhitehorn spin_lock_irqsave(&fsl_rio_config_lock, flags); 274217309Snwhitehorn 275217309Snwhitehorn out_be32(&priv->maint_atmu_regs->rowtar, 276217309Snwhitehorn (destid << 22) | (hopcount << 12) | (offset >> 12)); 277217309Snwhitehorn out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); 278217309Snwhitehorn 279217309Snwhitehorn data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); 280217309Snwhitehorn switch (len) { 281217309Snwhitehorn case 1: 282217309Snwhitehorn out_8((u8 *) data, val); 283217309Snwhitehorn break; 284217309Snwhitehorn case 2: 285217309Snwhitehorn out_be16((u16 *) data, val); 286217309Snwhitehorn break; 287217309Snwhitehorn case 4: 288217309Snwhitehorn out_be32((u32 *) data, val); 289217309Snwhitehorn break; 290217309Snwhitehorn default: 291217309Snwhitehorn ret = -EINVAL; 292217309Snwhitehorn } 293217309Snwhitehorn spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 294217309Snwhitehorn 295217309Snwhitehorn return ret; 296217309Snwhitehorn} 297217309Snwhitehorn 298217309Snwhitehornstatic void fsl_rio_inbound_mem_init(struct rio_priv *priv) 299217309Snwhitehorn{ 300217309Snwhitehorn int i; 301217309Snwhitehorn 302217309Snwhitehorn /* close inbound windows */ 303217309Snwhitehorn for (i = 0; i < RIO_INB_ATMU_COUNT; i++) 304217309Snwhitehorn out_be32(&priv->inb_atmu_regs[i].riwar, 0); 305217309Snwhitehorn} 306217309Snwhitehorn 307217309Snwhitehornstatic int fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, 308217309Snwhitehorn u64 rstart, u64 size, u32 flags) 309217309Snwhitehorn{ 310217309Snwhitehorn struct rio_priv *priv = mport->priv; 311217309Snwhitehorn u32 base_size; 312217309Snwhitehorn unsigned int base_size_log; 313217309Snwhitehorn u64 win_start, win_end; 314217309Snwhitehorn u32 riwar; 315217309Snwhitehorn int i; 316217309Snwhitehorn 317217309Snwhitehorn if ((size & (size - 1)) != 0 || size > 0x400000000ULL) 318217309Snwhitehorn return -EINVAL; 319217309Snwhitehorn 320217309Snwhitehorn base_size_log = ilog2(size); 321217309Snwhitehorn base_size = 1 << base_size_log; 322217309Snwhitehorn 323217309Snwhitehorn /* check if addresses are aligned with the window size */ 324217309Snwhitehorn if (lstart & (base_size - 1)) 325217309Snwhitehorn return -EINVAL; 326217309Snwhitehorn if (rstart & (base_size - 1)) 327217309Snwhitehorn return -EINVAL; 328217309Snwhitehorn 329217309Snwhitehorn /* check for conflicting ranges */ 330217309Snwhitehorn for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { 331217309Snwhitehorn riwar = in_be32(&priv->inb_atmu_regs[i].riwar); 332217309Snwhitehorn if ((riwar & RIWAR_ENABLE) == 0) 333217309Snwhitehorn continue; 334217309Snwhitehorn win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK)) 335217309Snwhitehorn << RIWBAR_BADD_VAL_SHIFT; 336217309Snwhitehorn win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1); 337217309Snwhitehorn if (rstart < win_end && (rstart + size) > win_start) 338217309Snwhitehorn return -EINVAL; 339217309Snwhitehorn } 340217309Snwhitehorn 341217309Snwhitehorn /* find unused atmu */ 342217309Snwhitehorn for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { 343217309Snwhitehorn riwar = in_be32(&priv->inb_atmu_regs[i].riwar); 344217309Snwhitehorn if ((riwar & RIWAR_ENABLE) == 0) 345217309Snwhitehorn break; 346217309Snwhitehorn } 347217309Snwhitehorn if (i >= RIO_INB_ATMU_COUNT) 348217309Snwhitehorn return -ENOMEM; 349217309Snwhitehorn 350217309Snwhitehorn out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT); 351217309Snwhitehorn out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT); 352217309Snwhitehorn out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL | 353217309Snwhitehorn RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1)); 354217309Snwhitehorn 355217309Snwhitehorn return 0; 356217309Snwhitehorn} 357217309Snwhitehorn 358217309Snwhitehornstatic void fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart) 359217309Snwhitehorn{ 360217309Snwhitehorn u32 win_start_shift, base_start_shift; 361217309Snwhitehorn struct rio_priv *priv = mport->priv; 362217309Snwhitehorn u32 riwar, riwtar; 363217309Snwhitehorn int i; 364217309Snwhitehorn 365217309Snwhitehorn /* skip default window */ 366217309Snwhitehorn base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT; 367217309Snwhitehorn for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { 368217309Snwhitehorn riwar = in_be32(&priv->inb_atmu_regs[i].riwar); 369217309Snwhitehorn if ((riwar & RIWAR_ENABLE) == 0) 370217309Snwhitehorn continue; 371217309Snwhitehorn 372217309Snwhitehorn riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar); 373217309Snwhitehorn win_start_shift = riwtar & RIWTAR_TRAD_MASK; 374217309Snwhitehorn if (win_start_shift == base_start_shift) { 375217309Snwhitehorn out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE); 376217309Snwhitehorn return; 377217309Snwhitehorn } 378217309Snwhitehorn } 379217309Snwhitehorn} 380217309Snwhitehorn 381217309Snwhitehornvoid fsl_rio_port_error_handler(int offset) 382217309Snwhitehorn{ 383217309Snwhitehorn /*XXX: Error recovery is not implemented, we just clear errors */ 384217309Snwhitehorn out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); 385217309Snwhitehorn 386217309Snwhitehorn if (offset == 0) { 387217309Snwhitehorn out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0); 388217309Snwhitehorn out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR); 389217309Snwhitehorn out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR); 390217309Snwhitehorn } else { 391217309Snwhitehorn out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0); 392217309Snwhitehorn out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR); 393217309Snwhitehorn out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR); 394217309Snwhitehorn } 395217309Snwhitehorn} 396217309Snwhitehornstatic inline void fsl_rio_info(struct device *dev, u32 ccsr) 397217309Snwhitehorn{ 398217309Snwhitehorn const char *str; 399217309Snwhitehorn if (ccsr & 1) { 400217309Snwhitehorn /* Serial phy */ 401217309Snwhitehorn switch (ccsr >> 30) { 402217309Snwhitehorn case 0: 403217309Snwhitehorn str = "1"; 404217309Snwhitehorn break; 405217309Snwhitehorn case 1: 406217309Snwhitehorn str = "4"; 407217309Snwhitehorn break; 408217309Snwhitehorn default: 409217309Snwhitehorn str = "Unknown"; 410217309Snwhitehorn break; 411217309Snwhitehorn } 412217309Snwhitehorn dev_info(dev, "Hardware port width: %s\n", str); 413217309Snwhitehorn 414217309Snwhitehorn switch ((ccsr >> 27) & 7) { 415217309Snwhitehorn case 0: 416217309Snwhitehorn str = "Single-lane 0"; 417217309Snwhitehorn break; 418217309Snwhitehorn case 1: 419217309Snwhitehorn str = "Single-lane 2"; 420217309Snwhitehorn break; 421217309Snwhitehorn case 2: 422217309Snwhitehorn str = "Four-lane"; 423217309Snwhitehorn break; 424217309Snwhitehorn default: 425217309Snwhitehorn str = "Unknown"; 426217309Snwhitehorn break; 427217309Snwhitehorn } 428217309Snwhitehorn dev_info(dev, "Training connection status: %s\n", str); 429217309Snwhitehorn } else { 430217309Snwhitehorn /* Parallel phy */ 431217309Snwhitehorn if (!(ccsr & 0x80000000)) 432217309Snwhitehorn dev_info(dev, "Output port operating in 8-bit mode\n"); 433217309Snwhitehorn if (!(ccsr & 0x08000000)) 434217309Snwhitehorn dev_info(dev, "Input port operating in 8-bit mode\n"); 435217309Snwhitehorn } 436217309Snwhitehorn} 437217309Snwhitehorn 438217309Snwhitehorn/** 439217309Snwhitehorn * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface 440217309Snwhitehorn * @dev: platform_device pointer 441217309Snwhitehorn * 442217309Snwhitehorn * Initializes MPC85xx RapidIO hardware interface, configures 443217309Snwhitehorn * master port with system-specific info, and registers the 444217309Snwhitehorn * master port with the RapidIO subsystem. 445217309Snwhitehorn */ 446217309Snwhitehornstatic int fsl_rio_setup(struct platform_device *dev) 447217309Snwhitehorn{ 448217309Snwhitehorn struct rio_ops *ops; 449217309Snwhitehorn struct rio_mport *port; 450217309Snwhitehorn struct rio_priv *priv; 451217309Snwhitehorn int rc = 0; 452217309Snwhitehorn const u32 *port_index; 453217309Snwhitehorn u32 active_ports = 0; 454217309Snwhitehorn struct device_node *np, *rmu_node; 455217309Snwhitehorn u32 ccsr; 456217309Snwhitehorn u64 range_start; 457217309Snwhitehorn u32 i; 458217309Snwhitehorn static int tmp; 459217309Snwhitehorn struct device_node *rmu_np[MAX_MSG_UNIT_NUM] = {NULL}; 460217309Snwhitehorn 461217309Snwhitehorn if (!dev->dev.of_node) { 462217309Snwhitehorn dev_err(&dev->dev, "Device OF-Node is NULL"); 463217309Snwhitehorn return -ENODEV; 464217309Snwhitehorn } 465217309Snwhitehorn 466217309Snwhitehorn rio_regs_win = of_iomap(dev->dev.of_node, 0); 467217309Snwhitehorn if (!rio_regs_win) { 468217309Snwhitehorn dev_err(&dev->dev, "Unable to map rio register window\n"); 469217309Snwhitehorn rc = -ENOMEM; 470217309Snwhitehorn goto err_rio_regs; 471217309Snwhitehorn } 472217309Snwhitehorn 473217309Snwhitehorn ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL); 474217309Snwhitehorn if (!ops) { 475217309Snwhitehorn rc = -ENOMEM; 476217309Snwhitehorn goto err_ops; 477217309Snwhitehorn } 478217309Snwhitehorn ops->lcread = fsl_local_config_read; 479217309Snwhitehorn ops->lcwrite = fsl_local_config_write; 480217309Snwhitehorn ops->cread = fsl_rio_config_read; 481217309Snwhitehorn ops->cwrite = fsl_rio_config_write; 482217309Snwhitehorn ops->dsend = fsl_rio_doorbell_send; 483217309Snwhitehorn ops->pwenable = fsl_rio_pw_enable; 484217309Snwhitehorn ops->open_outb_mbox = fsl_open_outb_mbox; 485217309Snwhitehorn ops->open_inb_mbox = fsl_open_inb_mbox; 486217309Snwhitehorn ops->close_outb_mbox = fsl_close_outb_mbox; 487217309Snwhitehorn ops->close_inb_mbox = fsl_close_inb_mbox; 488217309Snwhitehorn ops->add_outb_message = fsl_add_outb_message; 489217309Snwhitehorn ops->add_inb_buffer = fsl_add_inb_buffer; 490217309Snwhitehorn ops->get_inb_message = fsl_get_inb_message; 491217309Snwhitehorn ops->map_inb = fsl_map_inb_mem; 492217309Snwhitehorn ops->unmap_inb = fsl_unmap_inb_mem; 493217309Snwhitehorn 494217309Snwhitehorn rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0); 495217309Snwhitehorn if (!rmu_node) { 496217309Snwhitehorn dev_err(&dev->dev, "No valid fsl,srio-rmu-handle property\n"); 497217309Snwhitehorn rc = -ENOENT; 498217309Snwhitehorn goto err_rmu; 499217309Snwhitehorn } 500217309Snwhitehorn rmu_regs_win = of_iomap(rmu_node, 0); 501217309Snwhitehorn 502217309Snwhitehorn of_node_put(rmu_node); 503217309Snwhitehorn if (!rmu_regs_win) { 504217309Snwhitehorn dev_err(&dev->dev, "Unable to map rmu register window\n"); 505217309Snwhitehorn rc = -ENOMEM; 506217309Snwhitehorn goto err_rmu; 507217309Snwhitehorn } 508217309Snwhitehorn for_each_compatible_node(np, NULL, "fsl,srio-msg-unit") { 509217309Snwhitehorn rmu_np[tmp] = np; 510217309Snwhitehorn tmp++; 511217309Snwhitehorn } 512217309Snwhitehorn 513217309Snwhitehorn /*set up doobell node*/ 514217309Snwhitehorn np = of_find_compatible_node(NULL, NULL, "fsl,srio-dbell-unit"); 515217309Snwhitehorn if (!np) { 516217309Snwhitehorn dev_err(&dev->dev, "No fsl,srio-dbell-unit node\n"); 517217309Snwhitehorn rc = -ENODEV; 518217309Snwhitehorn goto err_dbell; 519217309Snwhitehorn } 520217309Snwhitehorn dbell = kzalloc(sizeof(struct fsl_rio_dbell), GFP_KERNEL); 521217309Snwhitehorn if (!(dbell)) { 522217309Snwhitehorn dev_err(&dev->dev, "Can't alloc memory for 'fsl_rio_dbell'\n"); 523217309Snwhitehorn rc = -ENOMEM; 524217309Snwhitehorn goto err_dbell; 525217309Snwhitehorn } 526217309Snwhitehorn dbell->dev = &dev->dev; 527217309Snwhitehorn dbell->bellirq = irq_of_parse_and_map(np, 1); 528217309Snwhitehorn dev_info(&dev->dev, "bellirq: %d\n", dbell->bellirq); 529217309Snwhitehorn 530217309Snwhitehorn if (of_property_read_reg(np, 0, &range_start, NULL)) { 531217309Snwhitehorn pr_err("%pOF: unable to find 'reg' property\n", 532217309Snwhitehorn np); 533217309Snwhitehorn rc = -ENOMEM; 534217309Snwhitehorn goto err_pw; 535217309Snwhitehorn } 536217309Snwhitehorn dbell->dbell_regs = (struct rio_dbell_regs *)(rmu_regs_win + 537217309Snwhitehorn (u32)range_start); 538217309Snwhitehorn 539217309Snwhitehorn /*set up port write node*/ 540217309Snwhitehorn np = of_find_compatible_node(NULL, NULL, "fsl,srio-port-write-unit"); 541217309Snwhitehorn if (!np) { 542217309Snwhitehorn dev_err(&dev->dev, "No fsl,srio-port-write-unit node\n"); 543217309Snwhitehorn rc = -ENODEV; 544217309Snwhitehorn goto err_pw; 545217309Snwhitehorn } 546217309Snwhitehorn pw = kzalloc(sizeof(struct fsl_rio_pw), GFP_KERNEL); 547217309Snwhitehorn if (!(pw)) { 548217309Snwhitehorn dev_err(&dev->dev, "Can't alloc memory for 'fsl_rio_pw'\n"); 549217309Snwhitehorn rc = -ENOMEM; 550217309Snwhitehorn goto err_pw; 551217309Snwhitehorn } 552217309Snwhitehorn pw->dev = &dev->dev; 553217309Snwhitehorn pw->pwirq = irq_of_parse_and_map(np, 0); 554217309Snwhitehorn dev_info(&dev->dev, "pwirq: %d\n", pw->pwirq); 555217309Snwhitehorn if (of_property_read_reg(np, 0, &range_start, NULL)) { 556217309Snwhitehorn pr_err("%pOF: unable to find 'reg' property\n", 557217309Snwhitehorn np); 558217309Snwhitehorn rc = -ENOMEM; 559217309Snwhitehorn goto err; 560217309Snwhitehorn } 561217309Snwhitehorn pw->pw_regs = (struct rio_pw_regs *)(rmu_regs_win + (u32)range_start); 562217309Snwhitehorn 563217309Snwhitehorn /*set up ports node*/ 564217309Snwhitehorn for_each_child_of_node(dev->dev.of_node, np) { 565217309Snwhitehorn struct resource res; 566217309Snwhitehorn 567217309Snwhitehorn port_index = of_get_property(np, "cell-index", NULL); 568217309Snwhitehorn if (!port_index) { 569217309Snwhitehorn dev_err(&dev->dev, "Can't get %pOF property 'cell-index'\n", 570217309Snwhitehorn np); 571217309Snwhitehorn continue; 572217309Snwhitehorn } 573217309Snwhitehorn 574217309Snwhitehorn if (of_range_to_resource(np, 0, &res)) { 575217309Snwhitehorn dev_err(&dev->dev, "Can't get %pOF property 'ranges'\n", 576217309Snwhitehorn np); 577217309Snwhitehorn continue; 578217309Snwhitehorn } 579217309Snwhitehorn 580217309Snwhitehorn dev_info(&dev->dev, "%pOF: LAW %pR\n", 581217309Snwhitehorn np, &res); 582217309Snwhitehorn 583217309Snwhitehorn port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); 584217309Snwhitehorn if (!port) 585217309Snwhitehorn continue; 586217309Snwhitehorn 587217309Snwhitehorn rc = rio_mport_initialize(port); 588217309Snwhitehorn if (rc) { 589217309Snwhitehorn kfree(port); 590217309Snwhitehorn continue; 591217309Snwhitehorn } 592217309Snwhitehorn 593217309Snwhitehorn i = *port_index - 1; 594217309Snwhitehorn port->index = (unsigned char)i; 595217309Snwhitehorn 596217309Snwhitehorn priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL); 597217309Snwhitehorn if (!priv) { 598217309Snwhitehorn dev_err(&dev->dev, "Can't alloc memory for 'priv'\n"); 599217309Snwhitehorn kfree(port); 600217309Snwhitehorn continue; 601217309Snwhitehorn } 602217309Snwhitehorn 603217309Snwhitehorn INIT_LIST_HEAD(&port->dbells); 604217309Snwhitehorn port->iores = res; /* struct copy */ 605217309Snwhitehorn port->iores.name = "rio_io_win"; 606217309Snwhitehorn 607217309Snwhitehorn if (request_resource(&iomem_resource, &port->iores) < 0) { 608217309Snwhitehorn dev_err(&dev->dev, "RIO: Error requesting master port region" 609217309Snwhitehorn " 0x%016llx-0x%016llx\n", 610217309Snwhitehorn (u64)port->iores.start, (u64)port->iores.end); 611217309Snwhitehorn kfree(priv); 612217309Snwhitehorn kfree(port); 613217309Snwhitehorn continue; 614217309Snwhitehorn } 615217309Snwhitehorn sprintf(port->name, "RIO mport %d", i); 616217309Snwhitehorn 617217309Snwhitehorn priv->dev = &dev->dev; 618217309Snwhitehorn port->dev.parent = &dev->dev; 619217309Snwhitehorn port->ops = ops; 620217309Snwhitehorn port->priv = priv; 621217309Snwhitehorn port->phys_efptr = 0x100; 622217309Snwhitehorn port->phys_rmap = 1; 623217309Snwhitehorn priv->regs_win = rio_regs_win; 624217309Snwhitehorn 625217309Snwhitehorn ccsr = in_be32(priv->regs_win + RIO_CCSR + i*0x20); 626217309Snwhitehorn 627217309Snwhitehorn /* Checking the port training status */ 628217309Snwhitehorn if (in_be32((priv->regs_win + RIO_ESCSR + i*0x20)) & 1) { 629217309Snwhitehorn dev_err(&dev->dev, "Port %d is not ready. " 630217309Snwhitehorn "Try to restart connection...\n", i); 631217309Snwhitehorn /* Disable ports */ 632217309Snwhitehorn out_be32(priv->regs_win 633217309Snwhitehorn + RIO_CCSR + i*0x20, 0); 634217309Snwhitehorn /* Set 1x lane */ 635217309Snwhitehorn setbits32(priv->regs_win 636217309Snwhitehorn + RIO_CCSR + i*0x20, 0x02000000); 637217309Snwhitehorn /* Enable ports */ 638217309Snwhitehorn setbits32(priv->regs_win 639217309Snwhitehorn + RIO_CCSR + i*0x20, 0x00600000); 640217309Snwhitehorn msleep(100); 641217309Snwhitehorn if (in_be32((priv->regs_win 642217309Snwhitehorn + RIO_ESCSR + i*0x20)) & 1) { 643217309Snwhitehorn dev_err(&dev->dev, 644217309Snwhitehorn "Port %d restart failed.\n", i); 645217309Snwhitehorn release_resource(&port->iores); 646217309Snwhitehorn kfree(priv); 647217309Snwhitehorn kfree(port); 648217309Snwhitehorn continue; 649217309Snwhitehorn } 650217309Snwhitehorn dev_info(&dev->dev, "Port %d restart success!\n", i); 651217309Snwhitehorn } 652217309Snwhitehorn fsl_rio_info(&dev->dev, ccsr); 653217309Snwhitehorn 654217309Snwhitehorn port->sys_size = (in_be32((priv->regs_win + RIO_PEF_CAR)) 655217309Snwhitehorn & RIO_PEF_CTLS) >> 4; 656217309Snwhitehorn dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n", 657217309Snwhitehorn port->sys_size ? 65536 : 256); 658217309Snwhitehorn 659217309Snwhitehorn if (port->host_deviceid >= 0) 660217309Snwhitehorn out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST | 661217309Snwhitehorn RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED); 662217309Snwhitehorn else 663217309Snwhitehorn out_be32(priv->regs_win + RIO_GCCSR, 664217309Snwhitehorn RIO_PORT_GEN_MASTER); 665217309Snwhitehorn 666217309Snwhitehorn priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win 667217309Snwhitehorn + ((i == 0) ? RIO_ATMU_REGS_PORT1_OFFSET : 668217309Snwhitehorn RIO_ATMU_REGS_PORT2_OFFSET)); 669217309Snwhitehorn 670217309Snwhitehorn priv->maint_atmu_regs = priv->atmu_regs + 1; 671217309Snwhitehorn priv->inb_atmu_regs = (struct rio_inb_atmu_regs __iomem *) 672217309Snwhitehorn (priv->regs_win + 673217309Snwhitehorn ((i == 0) ? RIO_INB_ATMU_REGS_PORT1_OFFSET : 674217309Snwhitehorn RIO_INB_ATMU_REGS_PORT2_OFFSET)); 675217309Snwhitehorn 676217309Snwhitehorn /* Set to receive packets with any dest ID */ 677217309Snwhitehorn out_be32((priv->regs_win + RIO_ISR_AACR + i*0x80), 678217309Snwhitehorn RIO_ISR_AACR_AA); 679217309Snwhitehorn 680217309Snwhitehorn /* Configure maintenance transaction window */ 681217309Snwhitehorn out_be32(&priv->maint_atmu_regs->rowbar, 682217309Snwhitehorn port->iores.start >> 12); 683217309Snwhitehorn out_be32(&priv->maint_atmu_regs->rowar, 684217309Snwhitehorn 0x80077000 | (ilog2(RIO_MAINT_WIN_SIZE) - 1)); 685217309Snwhitehorn 686217309Snwhitehorn priv->maint_win = ioremap(port->iores.start, 687217309Snwhitehorn RIO_MAINT_WIN_SIZE); 688217309Snwhitehorn 689217309Snwhitehorn rio_law_start = range_start; 690217309Snwhitehorn 691217309Snwhitehorn fsl_rio_setup_rmu(port, rmu_np[i]); 692217309Snwhitehorn fsl_rio_inbound_mem_init(priv); 693217309Snwhitehorn 694217309Snwhitehorn dbell->mport[i] = port; 695217309Snwhitehorn pw->mport[i] = port; 696217309Snwhitehorn 697217309Snwhitehorn if (rio_register_mport(port)) { 698217309Snwhitehorn release_resource(&port->iores); 699217309Snwhitehorn kfree(priv); 700217309Snwhitehorn kfree(port); 701217309Snwhitehorn continue; 702217309Snwhitehorn } 703217309Snwhitehorn active_ports++; 704217309Snwhitehorn } 705217309Snwhitehorn 706217309Snwhitehorn if (!active_ports) { 707217309Snwhitehorn rc = -ENOLINK; 708217309Snwhitehorn goto err; 709217309Snwhitehorn } 710217309Snwhitehorn 711217309Snwhitehorn fsl_rio_doorbell_init(dbell); 712217309Snwhitehorn fsl_rio_port_write_init(pw); 713217309Snwhitehorn 714217309Snwhitehorn return 0; 715217309Snwhitehornerr: 716217309Snwhitehorn kfree(pw); 717217309Snwhitehorn pw = NULL; 718217309Snwhitehornerr_pw: 719217309Snwhitehorn kfree(dbell); 720217309Snwhitehorn dbell = NULL; 721217309Snwhitehornerr_dbell: 722217309Snwhitehorn iounmap(rmu_regs_win); 723217309Snwhitehorn rmu_regs_win = NULL; 724217309Snwhitehornerr_rmu: 725217309Snwhitehorn kfree(ops); 726217309Snwhitehornerr_ops: 727217309Snwhitehorn iounmap(rio_regs_win); 728217309Snwhitehorn rio_regs_win = NULL; 729217309Snwhitehornerr_rio_regs: 730217309Snwhitehorn return rc; 731217309Snwhitehorn} 732217309Snwhitehorn 733217309Snwhitehorn/* The probe function for RapidIO peer-to-peer network. 734217309Snwhitehorn */ 735217309Snwhitehornstatic int fsl_of_rio_rpn_probe(struct platform_device *dev) 736217309Snwhitehorn{ 737217309Snwhitehorn printk(KERN_INFO "Setting up RapidIO peer-to-peer network %pOF\n", 738217309Snwhitehorn dev->dev.of_node); 739217309Snwhitehorn 740217309Snwhitehorn return fsl_rio_setup(dev); 741217309Snwhitehorn}; 742217309Snwhitehorn 743217309Snwhitehornstatic const struct of_device_id fsl_of_rio_rpn_ids[] = { 744217309Snwhitehorn { 745217309Snwhitehorn .compatible = "fsl,srio", 746217309Snwhitehorn }, 747217309Snwhitehorn {}, 748217309Snwhitehorn}; 749217309Snwhitehorn 750217309Snwhitehornstatic struct platform_driver fsl_of_rio_rpn_driver = { 751217309Snwhitehorn .driver = { 752217309Snwhitehorn .name = "fsl-of-rio", 753217309Snwhitehorn .of_match_table = fsl_of_rio_rpn_ids, 754217309Snwhitehorn }, 755217309Snwhitehorn .probe = fsl_of_rio_rpn_probe, 756217309Snwhitehorn}; 757217309Snwhitehorn 758217309Snwhitehornstatic __init int fsl_of_rio_rpn_init(void) 759217309Snwhitehorn{ 760217309Snwhitehorn return platform_driver_register(&fsl_of_rio_rpn_driver); 761217309Snwhitehorn} 762217309Snwhitehorn 763217309Snwhitehornsubsys_initcall(fsl_of_rio_rpn_init); 764217309Snwhitehorn