18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-or-later 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Freescale MPC85xx/MPC86xx RapidIO support 48c2ecf20Sopenharmony_ci * 58c2ecf20Sopenharmony_ci * Copyright 2009 Sysgo AG 68c2ecf20Sopenharmony_ci * Thomas Moll <thomas.moll@sysgo.com> 78c2ecf20Sopenharmony_ci * - fixed maintenance access routines, check for aligned access 88c2ecf20Sopenharmony_ci * 98c2ecf20Sopenharmony_ci * Copyright 2009 Integrated Device Technology, Inc. 108c2ecf20Sopenharmony_ci * Alex Bounine <alexandre.bounine@idt.com> 118c2ecf20Sopenharmony_ci * - Added Port-Write message handling 128c2ecf20Sopenharmony_ci * - Added Machine Check exception handling 138c2ecf20Sopenharmony_ci * 148c2ecf20Sopenharmony_ci * Copyright (C) 2007, 2008, 2010, 2011 Freescale Semiconductor, Inc. 158c2ecf20Sopenharmony_ci * Zhang Wei <wei.zhang@freescale.com> 168c2ecf20Sopenharmony_ci * 178c2ecf20Sopenharmony_ci * Copyright 2005 MontaVista Software, Inc. 188c2ecf20Sopenharmony_ci * Matt Porter <mporter@kernel.crashing.org> 198c2ecf20Sopenharmony_ci */ 208c2ecf20Sopenharmony_ci 218c2ecf20Sopenharmony_ci#include <linux/init.h> 228c2ecf20Sopenharmony_ci#include <linux/extable.h> 238c2ecf20Sopenharmony_ci#include <linux/types.h> 248c2ecf20Sopenharmony_ci#include <linux/dma-mapping.h> 258c2ecf20Sopenharmony_ci#include <linux/interrupt.h> 268c2ecf20Sopenharmony_ci#include <linux/device.h> 278c2ecf20Sopenharmony_ci#include <linux/of_address.h> 288c2ecf20Sopenharmony_ci#include <linux/of_irq.h> 298c2ecf20Sopenharmony_ci#include <linux/of_platform.h> 308c2ecf20Sopenharmony_ci#include <linux/delay.h> 318c2ecf20Sopenharmony_ci#include <linux/slab.h> 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_ci#include <linux/io.h> 348c2ecf20Sopenharmony_ci#include <linux/uaccess.h> 358c2ecf20Sopenharmony_ci#include <asm/machdep.h> 368c2ecf20Sopenharmony_ci 378c2ecf20Sopenharmony_ci#include "fsl_rio.h" 388c2ecf20Sopenharmony_ci 398c2ecf20Sopenharmony_ci#undef DEBUG_PW /* Port-Write debugging */ 408c2ecf20Sopenharmony_ci 418c2ecf20Sopenharmony_ci#define RIO_PORT1_EDCSR 0x0640 428c2ecf20Sopenharmony_ci#define RIO_PORT2_EDCSR 0x0680 438c2ecf20Sopenharmony_ci#define RIO_PORT1_IECSR 0x10130 448c2ecf20Sopenharmony_ci#define RIO_PORT2_IECSR 0x101B0 458c2ecf20Sopenharmony_ci 468c2ecf20Sopenharmony_ci#define RIO_GCCSR 0x13c 478c2ecf20Sopenharmony_ci#define RIO_ESCSR 0x158 488c2ecf20Sopenharmony_ci#define ESCSR_CLEAR 0x07120204 498c2ecf20Sopenharmony_ci#define RIO_PORT2_ESCSR 0x178 508c2ecf20Sopenharmony_ci#define RIO_CCSR 0x15c 518c2ecf20Sopenharmony_ci#define RIO_LTLEDCSR_IER 0x80000000 528c2ecf20Sopenharmony_ci#define RIO_LTLEDCSR_PRT 0x01000000 538c2ecf20Sopenharmony_ci#define IECSR_CLEAR 0x80000000 548c2ecf20Sopenharmony_ci#define RIO_ISR_AACR 0x10120 558c2ecf20Sopenharmony_ci#define RIO_ISR_AACR_AA 0x1 /* Accept All ID */ 568c2ecf20Sopenharmony_ci 578c2ecf20Sopenharmony_ci#define RIWTAR_TRAD_VAL_SHIFT 12 588c2ecf20Sopenharmony_ci#define RIWTAR_TRAD_MASK 0x00FFFFFF 598c2ecf20Sopenharmony_ci#define RIWBAR_BADD_VAL_SHIFT 12 608c2ecf20Sopenharmony_ci#define RIWBAR_BADD_MASK 0x003FFFFF 618c2ecf20Sopenharmony_ci#define RIWAR_ENABLE 0x80000000 628c2ecf20Sopenharmony_ci#define RIWAR_TGINT_LOCAL 0x00F00000 638c2ecf20Sopenharmony_ci#define RIWAR_RDTYP_NO_SNOOP 0x00040000 648c2ecf20Sopenharmony_ci#define RIWAR_RDTYP_SNOOP 0x00050000 658c2ecf20Sopenharmony_ci#define RIWAR_WRTYP_NO_SNOOP 0x00004000 668c2ecf20Sopenharmony_ci#define RIWAR_WRTYP_SNOOP 0x00005000 678c2ecf20Sopenharmony_ci#define RIWAR_WRTYP_ALLOC 0x00006000 688c2ecf20Sopenharmony_ci#define RIWAR_SIZE_MASK 0x0000003F 698c2ecf20Sopenharmony_ci 708c2ecf20Sopenharmony_cistatic DEFINE_SPINLOCK(fsl_rio_config_lock); 718c2ecf20Sopenharmony_ci 728c2ecf20Sopenharmony_ci#define __fsl_read_rio_config(x, addr, err, op) \ 738c2ecf20Sopenharmony_ci __asm__ __volatile__( \ 748c2ecf20Sopenharmony_ci "1: "op" %1,0(%2)\n" \ 758c2ecf20Sopenharmony_ci " eieio\n" \ 768c2ecf20Sopenharmony_ci "2:\n" \ 778c2ecf20Sopenharmony_ci ".section .fixup,\"ax\"\n" \ 788c2ecf20Sopenharmony_ci "3: li %1,-1\n" \ 798c2ecf20Sopenharmony_ci " li %0,%3\n" \ 808c2ecf20Sopenharmony_ci " b 2b\n" \ 818c2ecf20Sopenharmony_ci ".previous\n" \ 828c2ecf20Sopenharmony_ci EX_TABLE(1b, 3b) \ 838c2ecf20Sopenharmony_ci : "=r" (err), "=r" (x) \ 848c2ecf20Sopenharmony_ci : "b" (addr), "i" (-EFAULT), "0" (err)) 858c2ecf20Sopenharmony_ci 868c2ecf20Sopenharmony_civoid __iomem *rio_regs_win; 878c2ecf20Sopenharmony_civoid __iomem *rmu_regs_win; 888c2ecf20Sopenharmony_ciresource_size_t rio_law_start; 898c2ecf20Sopenharmony_ci 908c2ecf20Sopenharmony_cistruct fsl_rio_dbell *dbell; 918c2ecf20Sopenharmony_cistruct fsl_rio_pw *pw; 928c2ecf20Sopenharmony_ci 938c2ecf20Sopenharmony_ci#ifdef CONFIG_E500 948c2ecf20Sopenharmony_ciint fsl_rio_mcheck_exception(struct pt_regs *regs) 958c2ecf20Sopenharmony_ci{ 968c2ecf20Sopenharmony_ci const struct exception_table_entry *entry; 978c2ecf20Sopenharmony_ci unsigned long reason; 988c2ecf20Sopenharmony_ci 998c2ecf20Sopenharmony_ci if (!rio_regs_win) 1008c2ecf20Sopenharmony_ci return 0; 1018c2ecf20Sopenharmony_ci 1028c2ecf20Sopenharmony_ci reason = in_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR)); 1038c2ecf20Sopenharmony_ci if (reason & (RIO_LTLEDCSR_IER | RIO_LTLEDCSR_PRT)) { 1048c2ecf20Sopenharmony_ci /* Check if we are prepared to handle this fault */ 1058c2ecf20Sopenharmony_ci entry = search_exception_tables(regs->nip); 1068c2ecf20Sopenharmony_ci if (entry) { 1078c2ecf20Sopenharmony_ci pr_debug("RIO: %s - MC Exception handled\n", 1088c2ecf20Sopenharmony_ci __func__); 1098c2ecf20Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 1108c2ecf20Sopenharmony_ci 0); 1118c2ecf20Sopenharmony_ci regs->msr |= MSR_RI; 1128c2ecf20Sopenharmony_ci regs->nip = extable_fixup(entry); 1138c2ecf20Sopenharmony_ci return 1; 1148c2ecf20Sopenharmony_ci } 1158c2ecf20Sopenharmony_ci } 1168c2ecf20Sopenharmony_ci 1178c2ecf20Sopenharmony_ci return 0; 1188c2ecf20Sopenharmony_ci} 1198c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(fsl_rio_mcheck_exception); 1208c2ecf20Sopenharmony_ci#endif 1218c2ecf20Sopenharmony_ci 1228c2ecf20Sopenharmony_ci/** 1238c2ecf20Sopenharmony_ci * fsl_local_config_read - Generate a MPC85xx local config space read 1248c2ecf20Sopenharmony_ci * @mport: RapidIO master port info 1258c2ecf20Sopenharmony_ci * @index: ID of RapdiIO interface 1268c2ecf20Sopenharmony_ci * @offset: Offset into configuration space 1278c2ecf20Sopenharmony_ci * @len: Length (in bytes) of the maintenance transaction 1288c2ecf20Sopenharmony_ci * @data: Value to be read into 1298c2ecf20Sopenharmony_ci * 1308c2ecf20Sopenharmony_ci * Generates a MPC85xx local configuration space read. Returns %0 on 1318c2ecf20Sopenharmony_ci * success or %-EINVAL on failure. 1328c2ecf20Sopenharmony_ci */ 1338c2ecf20Sopenharmony_cistatic int fsl_local_config_read(struct rio_mport *mport, 1348c2ecf20Sopenharmony_ci int index, u32 offset, int len, u32 *data) 1358c2ecf20Sopenharmony_ci{ 1368c2ecf20Sopenharmony_ci struct rio_priv *priv = mport->priv; 1378c2ecf20Sopenharmony_ci pr_debug("fsl_local_config_read: index %d offset %8.8x\n", index, 1388c2ecf20Sopenharmony_ci offset); 1398c2ecf20Sopenharmony_ci *data = in_be32(priv->regs_win + offset); 1408c2ecf20Sopenharmony_ci 1418c2ecf20Sopenharmony_ci return 0; 1428c2ecf20Sopenharmony_ci} 1438c2ecf20Sopenharmony_ci 1448c2ecf20Sopenharmony_ci/** 1458c2ecf20Sopenharmony_ci * fsl_local_config_write - Generate a MPC85xx local config space write 1468c2ecf20Sopenharmony_ci * @mport: RapidIO master port info 1478c2ecf20Sopenharmony_ci * @index: ID of RapdiIO interface 1488c2ecf20Sopenharmony_ci * @offset: Offset into configuration space 1498c2ecf20Sopenharmony_ci * @len: Length (in bytes) of the maintenance transaction 1508c2ecf20Sopenharmony_ci * @data: Value to be written 1518c2ecf20Sopenharmony_ci * 1528c2ecf20Sopenharmony_ci * Generates a MPC85xx local configuration space write. Returns %0 on 1538c2ecf20Sopenharmony_ci * success or %-EINVAL on failure. 1548c2ecf20Sopenharmony_ci */ 1558c2ecf20Sopenharmony_cistatic int fsl_local_config_write(struct rio_mport *mport, 1568c2ecf20Sopenharmony_ci int index, u32 offset, int len, u32 data) 1578c2ecf20Sopenharmony_ci{ 1588c2ecf20Sopenharmony_ci struct rio_priv *priv = mport->priv; 1598c2ecf20Sopenharmony_ci pr_debug 1608c2ecf20Sopenharmony_ci ("fsl_local_config_write: index %d offset %8.8x data %8.8x\n", 1618c2ecf20Sopenharmony_ci index, offset, data); 1628c2ecf20Sopenharmony_ci out_be32(priv->regs_win + offset, data); 1638c2ecf20Sopenharmony_ci 1648c2ecf20Sopenharmony_ci return 0; 1658c2ecf20Sopenharmony_ci} 1668c2ecf20Sopenharmony_ci 1678c2ecf20Sopenharmony_ci/** 1688c2ecf20Sopenharmony_ci * fsl_rio_config_read - Generate a MPC85xx read maintenance transaction 1698c2ecf20Sopenharmony_ci * @mport: RapidIO master port info 1708c2ecf20Sopenharmony_ci * @index: ID of RapdiIO interface 1718c2ecf20Sopenharmony_ci * @destid: Destination ID of transaction 1728c2ecf20Sopenharmony_ci * @hopcount: Number of hops to target device 1738c2ecf20Sopenharmony_ci * @offset: Offset into configuration space 1748c2ecf20Sopenharmony_ci * @len: Length (in bytes) of the maintenance transaction 1758c2ecf20Sopenharmony_ci * @val: Location to be read into 1768c2ecf20Sopenharmony_ci * 1778c2ecf20Sopenharmony_ci * Generates a MPC85xx read maintenance transaction. Returns %0 on 1788c2ecf20Sopenharmony_ci * success or %-EINVAL on failure. 1798c2ecf20Sopenharmony_ci */ 1808c2ecf20Sopenharmony_cistatic int 1818c2ecf20Sopenharmony_cifsl_rio_config_read(struct rio_mport *mport, int index, u16 destid, 1828c2ecf20Sopenharmony_ci u8 hopcount, u32 offset, int len, u32 *val) 1838c2ecf20Sopenharmony_ci{ 1848c2ecf20Sopenharmony_ci struct rio_priv *priv = mport->priv; 1858c2ecf20Sopenharmony_ci unsigned long flags; 1868c2ecf20Sopenharmony_ci u8 *data; 1878c2ecf20Sopenharmony_ci u32 rval, err = 0; 1888c2ecf20Sopenharmony_ci 1898c2ecf20Sopenharmony_ci pr_debug 1908c2ecf20Sopenharmony_ci ("fsl_rio_config_read:" 1918c2ecf20Sopenharmony_ci " index %d destid %d hopcount %d offset %8.8x len %d\n", 1928c2ecf20Sopenharmony_ci index, destid, hopcount, offset, len); 1938c2ecf20Sopenharmony_ci 1948c2ecf20Sopenharmony_ci /* 16MB maintenance window possible */ 1958c2ecf20Sopenharmony_ci /* allow only aligned access to maintenance registers */ 1968c2ecf20Sopenharmony_ci if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) 1978c2ecf20Sopenharmony_ci return -EINVAL; 1988c2ecf20Sopenharmony_ci 1998c2ecf20Sopenharmony_ci spin_lock_irqsave(&fsl_rio_config_lock, flags); 2008c2ecf20Sopenharmony_ci 2018c2ecf20Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowtar, 2028c2ecf20Sopenharmony_ci (destid << 22) | (hopcount << 12) | (offset >> 12)); 2038c2ecf20Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); 2048c2ecf20Sopenharmony_ci 2058c2ecf20Sopenharmony_ci data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); 2068c2ecf20Sopenharmony_ci switch (len) { 2078c2ecf20Sopenharmony_ci case 1: 2088c2ecf20Sopenharmony_ci __fsl_read_rio_config(rval, data, err, "lbz"); 2098c2ecf20Sopenharmony_ci break; 2108c2ecf20Sopenharmony_ci case 2: 2118c2ecf20Sopenharmony_ci __fsl_read_rio_config(rval, data, err, "lhz"); 2128c2ecf20Sopenharmony_ci break; 2138c2ecf20Sopenharmony_ci case 4: 2148c2ecf20Sopenharmony_ci __fsl_read_rio_config(rval, data, err, "lwz"); 2158c2ecf20Sopenharmony_ci break; 2168c2ecf20Sopenharmony_ci default: 2178c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 2188c2ecf20Sopenharmony_ci return -EINVAL; 2198c2ecf20Sopenharmony_ci } 2208c2ecf20Sopenharmony_ci 2218c2ecf20Sopenharmony_ci if (err) { 2228c2ecf20Sopenharmony_ci pr_debug("RIO: cfg_read error %d for %x:%x:%x\n", 2238c2ecf20Sopenharmony_ci err, destid, hopcount, offset); 2248c2ecf20Sopenharmony_ci } 2258c2ecf20Sopenharmony_ci 2268c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 2278c2ecf20Sopenharmony_ci *val = rval; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci return err; 2308c2ecf20Sopenharmony_ci} 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci/** 2338c2ecf20Sopenharmony_ci * fsl_rio_config_write - Generate a MPC85xx write maintenance transaction 2348c2ecf20Sopenharmony_ci * @mport: RapidIO master port info 2358c2ecf20Sopenharmony_ci * @index: ID of RapdiIO interface 2368c2ecf20Sopenharmony_ci * @destid: Destination ID of transaction 2378c2ecf20Sopenharmony_ci * @hopcount: Number of hops to target device 2388c2ecf20Sopenharmony_ci * @offset: Offset into configuration space 2398c2ecf20Sopenharmony_ci * @len: Length (in bytes) of the maintenance transaction 2408c2ecf20Sopenharmony_ci * @val: Value to be written 2418c2ecf20Sopenharmony_ci * 2428c2ecf20Sopenharmony_ci * Generates an MPC85xx write maintenance transaction. Returns %0 on 2438c2ecf20Sopenharmony_ci * success or %-EINVAL on failure. 2448c2ecf20Sopenharmony_ci */ 2458c2ecf20Sopenharmony_cistatic int 2468c2ecf20Sopenharmony_cifsl_rio_config_write(struct rio_mport *mport, int index, u16 destid, 2478c2ecf20Sopenharmony_ci u8 hopcount, u32 offset, int len, u32 val) 2488c2ecf20Sopenharmony_ci{ 2498c2ecf20Sopenharmony_ci struct rio_priv *priv = mport->priv; 2508c2ecf20Sopenharmony_ci unsigned long flags; 2518c2ecf20Sopenharmony_ci u8 *data; 2528c2ecf20Sopenharmony_ci int ret = 0; 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_ci pr_debug 2558c2ecf20Sopenharmony_ci ("fsl_rio_config_write:" 2568c2ecf20Sopenharmony_ci " index %d destid %d hopcount %d offset %8.8x len %d val %8.8x\n", 2578c2ecf20Sopenharmony_ci index, destid, hopcount, offset, len, val); 2588c2ecf20Sopenharmony_ci 2598c2ecf20Sopenharmony_ci /* 16MB maintenance windows possible */ 2608c2ecf20Sopenharmony_ci /* allow only aligned access to maintenance registers */ 2618c2ecf20Sopenharmony_ci if (offset > (0x1000000 - len) || !IS_ALIGNED(offset, len)) 2628c2ecf20Sopenharmony_ci return -EINVAL; 2638c2ecf20Sopenharmony_ci 2648c2ecf20Sopenharmony_ci spin_lock_irqsave(&fsl_rio_config_lock, flags); 2658c2ecf20Sopenharmony_ci 2668c2ecf20Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowtar, 2678c2ecf20Sopenharmony_ci (destid << 22) | (hopcount << 12) | (offset >> 12)); 2688c2ecf20Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowtear, (destid >> 10)); 2698c2ecf20Sopenharmony_ci 2708c2ecf20Sopenharmony_ci data = (u8 *) priv->maint_win + (offset & (RIO_MAINT_WIN_SIZE - 1)); 2718c2ecf20Sopenharmony_ci switch (len) { 2728c2ecf20Sopenharmony_ci case 1: 2738c2ecf20Sopenharmony_ci out_8((u8 *) data, val); 2748c2ecf20Sopenharmony_ci break; 2758c2ecf20Sopenharmony_ci case 2: 2768c2ecf20Sopenharmony_ci out_be16((u16 *) data, val); 2778c2ecf20Sopenharmony_ci break; 2788c2ecf20Sopenharmony_ci case 4: 2798c2ecf20Sopenharmony_ci out_be32((u32 *) data, val); 2808c2ecf20Sopenharmony_ci break; 2818c2ecf20Sopenharmony_ci default: 2828c2ecf20Sopenharmony_ci ret = -EINVAL; 2838c2ecf20Sopenharmony_ci } 2848c2ecf20Sopenharmony_ci spin_unlock_irqrestore(&fsl_rio_config_lock, flags); 2858c2ecf20Sopenharmony_ci 2868c2ecf20Sopenharmony_ci return ret; 2878c2ecf20Sopenharmony_ci} 2888c2ecf20Sopenharmony_ci 2898c2ecf20Sopenharmony_cistatic void fsl_rio_inbound_mem_init(struct rio_priv *priv) 2908c2ecf20Sopenharmony_ci{ 2918c2ecf20Sopenharmony_ci int i; 2928c2ecf20Sopenharmony_ci 2938c2ecf20Sopenharmony_ci /* close inbound windows */ 2948c2ecf20Sopenharmony_ci for (i = 0; i < RIO_INB_ATMU_COUNT; i++) 2958c2ecf20Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwar, 0); 2968c2ecf20Sopenharmony_ci} 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ciint fsl_map_inb_mem(struct rio_mport *mport, dma_addr_t lstart, 2998c2ecf20Sopenharmony_ci u64 rstart, u64 size, u32 flags) 3008c2ecf20Sopenharmony_ci{ 3018c2ecf20Sopenharmony_ci struct rio_priv *priv = mport->priv; 3028c2ecf20Sopenharmony_ci u32 base_size; 3038c2ecf20Sopenharmony_ci unsigned int base_size_log; 3048c2ecf20Sopenharmony_ci u64 win_start, win_end; 3058c2ecf20Sopenharmony_ci u32 riwar; 3068c2ecf20Sopenharmony_ci int i; 3078c2ecf20Sopenharmony_ci 3088c2ecf20Sopenharmony_ci if ((size & (size - 1)) != 0 || size > 0x400000000ULL) 3098c2ecf20Sopenharmony_ci return -EINVAL; 3108c2ecf20Sopenharmony_ci 3118c2ecf20Sopenharmony_ci base_size_log = ilog2(size); 3128c2ecf20Sopenharmony_ci base_size = 1 << base_size_log; 3138c2ecf20Sopenharmony_ci 3148c2ecf20Sopenharmony_ci /* check if addresses are aligned with the window size */ 3158c2ecf20Sopenharmony_ci if (lstart & (base_size - 1)) 3168c2ecf20Sopenharmony_ci return -EINVAL; 3178c2ecf20Sopenharmony_ci if (rstart & (base_size - 1)) 3188c2ecf20Sopenharmony_ci return -EINVAL; 3198c2ecf20Sopenharmony_ci 3208c2ecf20Sopenharmony_ci /* check for conflicting ranges */ 3218c2ecf20Sopenharmony_ci for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { 3228c2ecf20Sopenharmony_ci riwar = in_be32(&priv->inb_atmu_regs[i].riwar); 3238c2ecf20Sopenharmony_ci if ((riwar & RIWAR_ENABLE) == 0) 3248c2ecf20Sopenharmony_ci continue; 3258c2ecf20Sopenharmony_ci win_start = ((u64)(in_be32(&priv->inb_atmu_regs[i].riwbar) & RIWBAR_BADD_MASK)) 3268c2ecf20Sopenharmony_ci << RIWBAR_BADD_VAL_SHIFT; 3278c2ecf20Sopenharmony_ci win_end = win_start + ((1 << ((riwar & RIWAR_SIZE_MASK) + 1)) - 1); 3288c2ecf20Sopenharmony_ci if (rstart < win_end && (rstart + size) > win_start) 3298c2ecf20Sopenharmony_ci return -EINVAL; 3308c2ecf20Sopenharmony_ci } 3318c2ecf20Sopenharmony_ci 3328c2ecf20Sopenharmony_ci /* find unused atmu */ 3338c2ecf20Sopenharmony_ci for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { 3348c2ecf20Sopenharmony_ci riwar = in_be32(&priv->inb_atmu_regs[i].riwar); 3358c2ecf20Sopenharmony_ci if ((riwar & RIWAR_ENABLE) == 0) 3368c2ecf20Sopenharmony_ci break; 3378c2ecf20Sopenharmony_ci } 3388c2ecf20Sopenharmony_ci if (i >= RIO_INB_ATMU_COUNT) 3398c2ecf20Sopenharmony_ci return -ENOMEM; 3408c2ecf20Sopenharmony_ci 3418c2ecf20Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwtar, lstart >> RIWTAR_TRAD_VAL_SHIFT); 3428c2ecf20Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwbar, rstart >> RIWBAR_BADD_VAL_SHIFT); 3438c2ecf20Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwar, RIWAR_ENABLE | RIWAR_TGINT_LOCAL | 3448c2ecf20Sopenharmony_ci RIWAR_RDTYP_SNOOP | RIWAR_WRTYP_SNOOP | (base_size_log - 1)); 3458c2ecf20Sopenharmony_ci 3468c2ecf20Sopenharmony_ci return 0; 3478c2ecf20Sopenharmony_ci} 3488c2ecf20Sopenharmony_ci 3498c2ecf20Sopenharmony_civoid fsl_unmap_inb_mem(struct rio_mport *mport, dma_addr_t lstart) 3508c2ecf20Sopenharmony_ci{ 3518c2ecf20Sopenharmony_ci u32 win_start_shift, base_start_shift; 3528c2ecf20Sopenharmony_ci struct rio_priv *priv = mport->priv; 3538c2ecf20Sopenharmony_ci u32 riwar, riwtar; 3548c2ecf20Sopenharmony_ci int i; 3558c2ecf20Sopenharmony_ci 3568c2ecf20Sopenharmony_ci /* skip default window */ 3578c2ecf20Sopenharmony_ci base_start_shift = lstart >> RIWTAR_TRAD_VAL_SHIFT; 3588c2ecf20Sopenharmony_ci for (i = 0; i < RIO_INB_ATMU_COUNT; i++) { 3598c2ecf20Sopenharmony_ci riwar = in_be32(&priv->inb_atmu_regs[i].riwar); 3608c2ecf20Sopenharmony_ci if ((riwar & RIWAR_ENABLE) == 0) 3618c2ecf20Sopenharmony_ci continue; 3628c2ecf20Sopenharmony_ci 3638c2ecf20Sopenharmony_ci riwtar = in_be32(&priv->inb_atmu_regs[i].riwtar); 3648c2ecf20Sopenharmony_ci win_start_shift = riwtar & RIWTAR_TRAD_MASK; 3658c2ecf20Sopenharmony_ci if (win_start_shift == base_start_shift) { 3668c2ecf20Sopenharmony_ci out_be32(&priv->inb_atmu_regs[i].riwar, riwar & ~RIWAR_ENABLE); 3678c2ecf20Sopenharmony_ci return; 3688c2ecf20Sopenharmony_ci } 3698c2ecf20Sopenharmony_ci } 3708c2ecf20Sopenharmony_ci} 3718c2ecf20Sopenharmony_ci 3728c2ecf20Sopenharmony_civoid fsl_rio_port_error_handler(int offset) 3738c2ecf20Sopenharmony_ci{ 3748c2ecf20Sopenharmony_ci /*XXX: Error recovery is not implemented, we just clear errors */ 3758c2ecf20Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_LTLEDCSR), 0); 3768c2ecf20Sopenharmony_ci 3778c2ecf20Sopenharmony_ci if (offset == 0) { 3788c2ecf20Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT1_EDCSR), 0); 3798c2ecf20Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT1_IECSR), IECSR_CLEAR); 3808c2ecf20Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_ESCSR), ESCSR_CLEAR); 3818c2ecf20Sopenharmony_ci } else { 3828c2ecf20Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT2_EDCSR), 0); 3838c2ecf20Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT2_IECSR), IECSR_CLEAR); 3848c2ecf20Sopenharmony_ci out_be32((u32 *)(rio_regs_win + RIO_PORT2_ESCSR), ESCSR_CLEAR); 3858c2ecf20Sopenharmony_ci } 3868c2ecf20Sopenharmony_ci} 3878c2ecf20Sopenharmony_cistatic inline void fsl_rio_info(struct device *dev, u32 ccsr) 3888c2ecf20Sopenharmony_ci{ 3898c2ecf20Sopenharmony_ci const char *str; 3908c2ecf20Sopenharmony_ci if (ccsr & 1) { 3918c2ecf20Sopenharmony_ci /* Serial phy */ 3928c2ecf20Sopenharmony_ci switch (ccsr >> 30) { 3938c2ecf20Sopenharmony_ci case 0: 3948c2ecf20Sopenharmony_ci str = "1"; 3958c2ecf20Sopenharmony_ci break; 3968c2ecf20Sopenharmony_ci case 1: 3978c2ecf20Sopenharmony_ci str = "4"; 3988c2ecf20Sopenharmony_ci break; 3998c2ecf20Sopenharmony_ci default: 4008c2ecf20Sopenharmony_ci str = "Unknown"; 4018c2ecf20Sopenharmony_ci break; 4028c2ecf20Sopenharmony_ci } 4038c2ecf20Sopenharmony_ci dev_info(dev, "Hardware port width: %s\n", str); 4048c2ecf20Sopenharmony_ci 4058c2ecf20Sopenharmony_ci switch ((ccsr >> 27) & 7) { 4068c2ecf20Sopenharmony_ci case 0: 4078c2ecf20Sopenharmony_ci str = "Single-lane 0"; 4088c2ecf20Sopenharmony_ci break; 4098c2ecf20Sopenharmony_ci case 1: 4108c2ecf20Sopenharmony_ci str = "Single-lane 2"; 4118c2ecf20Sopenharmony_ci break; 4128c2ecf20Sopenharmony_ci case 2: 4138c2ecf20Sopenharmony_ci str = "Four-lane"; 4148c2ecf20Sopenharmony_ci break; 4158c2ecf20Sopenharmony_ci default: 4168c2ecf20Sopenharmony_ci str = "Unknown"; 4178c2ecf20Sopenharmony_ci break; 4188c2ecf20Sopenharmony_ci } 4198c2ecf20Sopenharmony_ci dev_info(dev, "Training connection status: %s\n", str); 4208c2ecf20Sopenharmony_ci } else { 4218c2ecf20Sopenharmony_ci /* Parallel phy */ 4228c2ecf20Sopenharmony_ci if (!(ccsr & 0x80000000)) 4238c2ecf20Sopenharmony_ci dev_info(dev, "Output port operating in 8-bit mode\n"); 4248c2ecf20Sopenharmony_ci if (!(ccsr & 0x08000000)) 4258c2ecf20Sopenharmony_ci dev_info(dev, "Input port operating in 8-bit mode\n"); 4268c2ecf20Sopenharmony_ci } 4278c2ecf20Sopenharmony_ci} 4288c2ecf20Sopenharmony_ci 4298c2ecf20Sopenharmony_ci/** 4308c2ecf20Sopenharmony_ci * fsl_rio_setup - Setup Freescale PowerPC RapidIO interface 4318c2ecf20Sopenharmony_ci * @dev: platform_device pointer 4328c2ecf20Sopenharmony_ci * 4338c2ecf20Sopenharmony_ci * Initializes MPC85xx RapidIO hardware interface, configures 4348c2ecf20Sopenharmony_ci * master port with system-specific info, and registers the 4358c2ecf20Sopenharmony_ci * master port with the RapidIO subsystem. 4368c2ecf20Sopenharmony_ci */ 4378c2ecf20Sopenharmony_ciint fsl_rio_setup(struct platform_device *dev) 4388c2ecf20Sopenharmony_ci{ 4398c2ecf20Sopenharmony_ci struct rio_ops *ops; 4408c2ecf20Sopenharmony_ci struct rio_mport *port; 4418c2ecf20Sopenharmony_ci struct rio_priv *priv; 4428c2ecf20Sopenharmony_ci int rc = 0; 4438c2ecf20Sopenharmony_ci const u32 *dt_range, *cell, *port_index; 4448c2ecf20Sopenharmony_ci u32 active_ports = 0; 4458c2ecf20Sopenharmony_ci struct resource regs, rmu_regs; 4468c2ecf20Sopenharmony_ci struct device_node *np, *rmu_node; 4478c2ecf20Sopenharmony_ci int rlen; 4488c2ecf20Sopenharmony_ci u32 ccsr; 4498c2ecf20Sopenharmony_ci u64 range_start, range_size; 4508c2ecf20Sopenharmony_ci int paw, aw, sw; 4518c2ecf20Sopenharmony_ci u32 i; 4528c2ecf20Sopenharmony_ci static int tmp; 4538c2ecf20Sopenharmony_ci struct device_node *rmu_np[MAX_MSG_UNIT_NUM] = {NULL}; 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci if (!dev->dev.of_node) { 4568c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Device OF-Node is NULL"); 4578c2ecf20Sopenharmony_ci return -ENODEV; 4588c2ecf20Sopenharmony_ci } 4598c2ecf20Sopenharmony_ci 4608c2ecf20Sopenharmony_ci rc = of_address_to_resource(dev->dev.of_node, 0, ®s); 4618c2ecf20Sopenharmony_ci if (rc) { 4628c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Can't get %pOF property 'reg'\n", 4638c2ecf20Sopenharmony_ci dev->dev.of_node); 4648c2ecf20Sopenharmony_ci return -EFAULT; 4658c2ecf20Sopenharmony_ci } 4668c2ecf20Sopenharmony_ci dev_info(&dev->dev, "Of-device full name %pOF\n", 4678c2ecf20Sopenharmony_ci dev->dev.of_node); 4688c2ecf20Sopenharmony_ci dev_info(&dev->dev, "Regs: %pR\n", ®s); 4698c2ecf20Sopenharmony_ci 4708c2ecf20Sopenharmony_ci rio_regs_win = ioremap(regs.start, resource_size(®s)); 4718c2ecf20Sopenharmony_ci if (!rio_regs_win) { 4728c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Unable to map rio register window\n"); 4738c2ecf20Sopenharmony_ci rc = -ENOMEM; 4748c2ecf20Sopenharmony_ci goto err_rio_regs; 4758c2ecf20Sopenharmony_ci } 4768c2ecf20Sopenharmony_ci 4778c2ecf20Sopenharmony_ci ops = kzalloc(sizeof(struct rio_ops), GFP_KERNEL); 4788c2ecf20Sopenharmony_ci if (!ops) { 4798c2ecf20Sopenharmony_ci rc = -ENOMEM; 4808c2ecf20Sopenharmony_ci goto err_ops; 4818c2ecf20Sopenharmony_ci } 4828c2ecf20Sopenharmony_ci ops->lcread = fsl_local_config_read; 4838c2ecf20Sopenharmony_ci ops->lcwrite = fsl_local_config_write; 4848c2ecf20Sopenharmony_ci ops->cread = fsl_rio_config_read; 4858c2ecf20Sopenharmony_ci ops->cwrite = fsl_rio_config_write; 4868c2ecf20Sopenharmony_ci ops->dsend = fsl_rio_doorbell_send; 4878c2ecf20Sopenharmony_ci ops->pwenable = fsl_rio_pw_enable; 4888c2ecf20Sopenharmony_ci ops->open_outb_mbox = fsl_open_outb_mbox; 4898c2ecf20Sopenharmony_ci ops->open_inb_mbox = fsl_open_inb_mbox; 4908c2ecf20Sopenharmony_ci ops->close_outb_mbox = fsl_close_outb_mbox; 4918c2ecf20Sopenharmony_ci ops->close_inb_mbox = fsl_close_inb_mbox; 4928c2ecf20Sopenharmony_ci ops->add_outb_message = fsl_add_outb_message; 4938c2ecf20Sopenharmony_ci ops->add_inb_buffer = fsl_add_inb_buffer; 4948c2ecf20Sopenharmony_ci ops->get_inb_message = fsl_get_inb_message; 4958c2ecf20Sopenharmony_ci ops->map_inb = fsl_map_inb_mem; 4968c2ecf20Sopenharmony_ci ops->unmap_inb = fsl_unmap_inb_mem; 4978c2ecf20Sopenharmony_ci 4988c2ecf20Sopenharmony_ci rmu_node = of_parse_phandle(dev->dev.of_node, "fsl,srio-rmu-handle", 0); 4998c2ecf20Sopenharmony_ci if (!rmu_node) { 5008c2ecf20Sopenharmony_ci dev_err(&dev->dev, "No valid fsl,srio-rmu-handle property\n"); 5018c2ecf20Sopenharmony_ci rc = -ENOENT; 5028c2ecf20Sopenharmony_ci goto err_rmu; 5038c2ecf20Sopenharmony_ci } 5048c2ecf20Sopenharmony_ci rc = of_address_to_resource(rmu_node, 0, &rmu_regs); 5058c2ecf20Sopenharmony_ci if (rc) { 5068c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Can't get %pOF property 'reg'\n", 5078c2ecf20Sopenharmony_ci rmu_node); 5088c2ecf20Sopenharmony_ci of_node_put(rmu_node); 5098c2ecf20Sopenharmony_ci goto err_rmu; 5108c2ecf20Sopenharmony_ci } 5118c2ecf20Sopenharmony_ci of_node_put(rmu_node); 5128c2ecf20Sopenharmony_ci rmu_regs_win = ioremap(rmu_regs.start, resource_size(&rmu_regs)); 5138c2ecf20Sopenharmony_ci if (!rmu_regs_win) { 5148c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Unable to map rmu register window\n"); 5158c2ecf20Sopenharmony_ci rc = -ENOMEM; 5168c2ecf20Sopenharmony_ci goto err_rmu; 5178c2ecf20Sopenharmony_ci } 5188c2ecf20Sopenharmony_ci for_each_compatible_node(np, NULL, "fsl,srio-msg-unit") { 5198c2ecf20Sopenharmony_ci rmu_np[tmp] = np; 5208c2ecf20Sopenharmony_ci tmp++; 5218c2ecf20Sopenharmony_ci } 5228c2ecf20Sopenharmony_ci 5238c2ecf20Sopenharmony_ci /*set up doobell node*/ 5248c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,srio-dbell-unit"); 5258c2ecf20Sopenharmony_ci if (!np) { 5268c2ecf20Sopenharmony_ci dev_err(&dev->dev, "No fsl,srio-dbell-unit node\n"); 5278c2ecf20Sopenharmony_ci rc = -ENODEV; 5288c2ecf20Sopenharmony_ci goto err_dbell; 5298c2ecf20Sopenharmony_ci } 5308c2ecf20Sopenharmony_ci dbell = kzalloc(sizeof(struct fsl_rio_dbell), GFP_KERNEL); 5318c2ecf20Sopenharmony_ci if (!(dbell)) { 5328c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Can't alloc memory for 'fsl_rio_dbell'\n"); 5338c2ecf20Sopenharmony_ci rc = -ENOMEM; 5348c2ecf20Sopenharmony_ci goto err_dbell; 5358c2ecf20Sopenharmony_ci } 5368c2ecf20Sopenharmony_ci dbell->dev = &dev->dev; 5378c2ecf20Sopenharmony_ci dbell->bellirq = irq_of_parse_and_map(np, 1); 5388c2ecf20Sopenharmony_ci dev_info(&dev->dev, "bellirq: %d\n", dbell->bellirq); 5398c2ecf20Sopenharmony_ci 5408c2ecf20Sopenharmony_ci aw = of_n_addr_cells(np); 5418c2ecf20Sopenharmony_ci dt_range = of_get_property(np, "reg", &rlen); 5428c2ecf20Sopenharmony_ci if (!dt_range) { 5438c2ecf20Sopenharmony_ci pr_err("%pOF: unable to find 'reg' property\n", 5448c2ecf20Sopenharmony_ci np); 5458c2ecf20Sopenharmony_ci rc = -ENOMEM; 5468c2ecf20Sopenharmony_ci goto err_pw; 5478c2ecf20Sopenharmony_ci } 5488c2ecf20Sopenharmony_ci range_start = of_read_number(dt_range, aw); 5498c2ecf20Sopenharmony_ci dbell->dbell_regs = (struct rio_dbell_regs *)(rmu_regs_win + 5508c2ecf20Sopenharmony_ci (u32)range_start); 5518c2ecf20Sopenharmony_ci 5528c2ecf20Sopenharmony_ci /*set up port write node*/ 5538c2ecf20Sopenharmony_ci np = of_find_compatible_node(NULL, NULL, "fsl,srio-port-write-unit"); 5548c2ecf20Sopenharmony_ci if (!np) { 5558c2ecf20Sopenharmony_ci dev_err(&dev->dev, "No fsl,srio-port-write-unit node\n"); 5568c2ecf20Sopenharmony_ci rc = -ENODEV; 5578c2ecf20Sopenharmony_ci goto err_pw; 5588c2ecf20Sopenharmony_ci } 5598c2ecf20Sopenharmony_ci pw = kzalloc(sizeof(struct fsl_rio_pw), GFP_KERNEL); 5608c2ecf20Sopenharmony_ci if (!(pw)) { 5618c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Can't alloc memory for 'fsl_rio_pw'\n"); 5628c2ecf20Sopenharmony_ci rc = -ENOMEM; 5638c2ecf20Sopenharmony_ci goto err_pw; 5648c2ecf20Sopenharmony_ci } 5658c2ecf20Sopenharmony_ci pw->dev = &dev->dev; 5668c2ecf20Sopenharmony_ci pw->pwirq = irq_of_parse_and_map(np, 0); 5678c2ecf20Sopenharmony_ci dev_info(&dev->dev, "pwirq: %d\n", pw->pwirq); 5688c2ecf20Sopenharmony_ci aw = of_n_addr_cells(np); 5698c2ecf20Sopenharmony_ci dt_range = of_get_property(np, "reg", &rlen); 5708c2ecf20Sopenharmony_ci if (!dt_range) { 5718c2ecf20Sopenharmony_ci pr_err("%pOF: unable to find 'reg' property\n", 5728c2ecf20Sopenharmony_ci np); 5738c2ecf20Sopenharmony_ci rc = -ENOMEM; 5748c2ecf20Sopenharmony_ci goto err; 5758c2ecf20Sopenharmony_ci } 5768c2ecf20Sopenharmony_ci range_start = of_read_number(dt_range, aw); 5778c2ecf20Sopenharmony_ci pw->pw_regs = (struct rio_pw_regs *)(rmu_regs_win + (u32)range_start); 5788c2ecf20Sopenharmony_ci 5798c2ecf20Sopenharmony_ci /*set up ports node*/ 5808c2ecf20Sopenharmony_ci for_each_child_of_node(dev->dev.of_node, np) { 5818c2ecf20Sopenharmony_ci port_index = of_get_property(np, "cell-index", NULL); 5828c2ecf20Sopenharmony_ci if (!port_index) { 5838c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Can't get %pOF property 'cell-index'\n", 5848c2ecf20Sopenharmony_ci np); 5858c2ecf20Sopenharmony_ci continue; 5868c2ecf20Sopenharmony_ci } 5878c2ecf20Sopenharmony_ci 5888c2ecf20Sopenharmony_ci dt_range = of_get_property(np, "ranges", &rlen); 5898c2ecf20Sopenharmony_ci if (!dt_range) { 5908c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Can't get %pOF property 'ranges'\n", 5918c2ecf20Sopenharmony_ci np); 5928c2ecf20Sopenharmony_ci continue; 5938c2ecf20Sopenharmony_ci } 5948c2ecf20Sopenharmony_ci 5958c2ecf20Sopenharmony_ci /* Get node address wide */ 5968c2ecf20Sopenharmony_ci cell = of_get_property(np, "#address-cells", NULL); 5978c2ecf20Sopenharmony_ci if (cell) 5988c2ecf20Sopenharmony_ci aw = *cell; 5998c2ecf20Sopenharmony_ci else 6008c2ecf20Sopenharmony_ci aw = of_n_addr_cells(np); 6018c2ecf20Sopenharmony_ci /* Get node size wide */ 6028c2ecf20Sopenharmony_ci cell = of_get_property(np, "#size-cells", NULL); 6038c2ecf20Sopenharmony_ci if (cell) 6048c2ecf20Sopenharmony_ci sw = *cell; 6058c2ecf20Sopenharmony_ci else 6068c2ecf20Sopenharmony_ci sw = of_n_size_cells(np); 6078c2ecf20Sopenharmony_ci /* Get parent address wide wide */ 6088c2ecf20Sopenharmony_ci paw = of_n_addr_cells(np); 6098c2ecf20Sopenharmony_ci range_start = of_read_number(dt_range + aw, paw); 6108c2ecf20Sopenharmony_ci range_size = of_read_number(dt_range + aw + paw, sw); 6118c2ecf20Sopenharmony_ci 6128c2ecf20Sopenharmony_ci dev_info(&dev->dev, "%pOF: LAW start 0x%016llx, size 0x%016llx.\n", 6138c2ecf20Sopenharmony_ci np, range_start, range_size); 6148c2ecf20Sopenharmony_ci 6158c2ecf20Sopenharmony_ci port = kzalloc(sizeof(struct rio_mport), GFP_KERNEL); 6168c2ecf20Sopenharmony_ci if (!port) 6178c2ecf20Sopenharmony_ci continue; 6188c2ecf20Sopenharmony_ci 6198c2ecf20Sopenharmony_ci rc = rio_mport_initialize(port); 6208c2ecf20Sopenharmony_ci if (rc) { 6218c2ecf20Sopenharmony_ci kfree(port); 6228c2ecf20Sopenharmony_ci continue; 6238c2ecf20Sopenharmony_ci } 6248c2ecf20Sopenharmony_ci 6258c2ecf20Sopenharmony_ci i = *port_index - 1; 6268c2ecf20Sopenharmony_ci port->index = (unsigned char)i; 6278c2ecf20Sopenharmony_ci 6288c2ecf20Sopenharmony_ci priv = kzalloc(sizeof(struct rio_priv), GFP_KERNEL); 6298c2ecf20Sopenharmony_ci if (!priv) { 6308c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Can't alloc memory for 'priv'\n"); 6318c2ecf20Sopenharmony_ci kfree(port); 6328c2ecf20Sopenharmony_ci continue; 6338c2ecf20Sopenharmony_ci } 6348c2ecf20Sopenharmony_ci 6358c2ecf20Sopenharmony_ci INIT_LIST_HEAD(&port->dbells); 6368c2ecf20Sopenharmony_ci port->iores.start = range_start; 6378c2ecf20Sopenharmony_ci port->iores.end = port->iores.start + range_size - 1; 6388c2ecf20Sopenharmony_ci port->iores.flags = IORESOURCE_MEM; 6398c2ecf20Sopenharmony_ci port->iores.name = "rio_io_win"; 6408c2ecf20Sopenharmony_ci 6418c2ecf20Sopenharmony_ci if (request_resource(&iomem_resource, &port->iores) < 0) { 6428c2ecf20Sopenharmony_ci dev_err(&dev->dev, "RIO: Error requesting master port region" 6438c2ecf20Sopenharmony_ci " 0x%016llx-0x%016llx\n", 6448c2ecf20Sopenharmony_ci (u64)port->iores.start, (u64)port->iores.end); 6458c2ecf20Sopenharmony_ci kfree(priv); 6468c2ecf20Sopenharmony_ci kfree(port); 6478c2ecf20Sopenharmony_ci continue; 6488c2ecf20Sopenharmony_ci } 6498c2ecf20Sopenharmony_ci sprintf(port->name, "RIO mport %d", i); 6508c2ecf20Sopenharmony_ci 6518c2ecf20Sopenharmony_ci priv->dev = &dev->dev; 6528c2ecf20Sopenharmony_ci port->dev.parent = &dev->dev; 6538c2ecf20Sopenharmony_ci port->ops = ops; 6548c2ecf20Sopenharmony_ci port->priv = priv; 6558c2ecf20Sopenharmony_ci port->phys_efptr = 0x100; 6568c2ecf20Sopenharmony_ci port->phys_rmap = 1; 6578c2ecf20Sopenharmony_ci priv->regs_win = rio_regs_win; 6588c2ecf20Sopenharmony_ci 6598c2ecf20Sopenharmony_ci ccsr = in_be32(priv->regs_win + RIO_CCSR + i*0x20); 6608c2ecf20Sopenharmony_ci 6618c2ecf20Sopenharmony_ci /* Checking the port training status */ 6628c2ecf20Sopenharmony_ci if (in_be32((priv->regs_win + RIO_ESCSR + i*0x20)) & 1) { 6638c2ecf20Sopenharmony_ci dev_err(&dev->dev, "Port %d is not ready. " 6648c2ecf20Sopenharmony_ci "Try to restart connection...\n", i); 6658c2ecf20Sopenharmony_ci /* Disable ports */ 6668c2ecf20Sopenharmony_ci out_be32(priv->regs_win 6678c2ecf20Sopenharmony_ci + RIO_CCSR + i*0x20, 0); 6688c2ecf20Sopenharmony_ci /* Set 1x lane */ 6698c2ecf20Sopenharmony_ci setbits32(priv->regs_win 6708c2ecf20Sopenharmony_ci + RIO_CCSR + i*0x20, 0x02000000); 6718c2ecf20Sopenharmony_ci /* Enable ports */ 6728c2ecf20Sopenharmony_ci setbits32(priv->regs_win 6738c2ecf20Sopenharmony_ci + RIO_CCSR + i*0x20, 0x00600000); 6748c2ecf20Sopenharmony_ci msleep(100); 6758c2ecf20Sopenharmony_ci if (in_be32((priv->regs_win 6768c2ecf20Sopenharmony_ci + RIO_ESCSR + i*0x20)) & 1) { 6778c2ecf20Sopenharmony_ci dev_err(&dev->dev, 6788c2ecf20Sopenharmony_ci "Port %d restart failed.\n", i); 6798c2ecf20Sopenharmony_ci release_resource(&port->iores); 6808c2ecf20Sopenharmony_ci kfree(priv); 6818c2ecf20Sopenharmony_ci kfree(port); 6828c2ecf20Sopenharmony_ci continue; 6838c2ecf20Sopenharmony_ci } 6848c2ecf20Sopenharmony_ci dev_info(&dev->dev, "Port %d restart success!\n", i); 6858c2ecf20Sopenharmony_ci } 6868c2ecf20Sopenharmony_ci fsl_rio_info(&dev->dev, ccsr); 6878c2ecf20Sopenharmony_ci 6888c2ecf20Sopenharmony_ci port->sys_size = (in_be32((priv->regs_win + RIO_PEF_CAR)) 6898c2ecf20Sopenharmony_ci & RIO_PEF_CTLS) >> 4; 6908c2ecf20Sopenharmony_ci dev_info(&dev->dev, "RapidIO Common Transport System size: %d\n", 6918c2ecf20Sopenharmony_ci port->sys_size ? 65536 : 256); 6928c2ecf20Sopenharmony_ci 6938c2ecf20Sopenharmony_ci if (port->host_deviceid >= 0) 6948c2ecf20Sopenharmony_ci out_be32(priv->regs_win + RIO_GCCSR, RIO_PORT_GEN_HOST | 6958c2ecf20Sopenharmony_ci RIO_PORT_GEN_MASTER | RIO_PORT_GEN_DISCOVERED); 6968c2ecf20Sopenharmony_ci else 6978c2ecf20Sopenharmony_ci out_be32(priv->regs_win + RIO_GCCSR, 6988c2ecf20Sopenharmony_ci RIO_PORT_GEN_MASTER); 6998c2ecf20Sopenharmony_ci 7008c2ecf20Sopenharmony_ci priv->atmu_regs = (struct rio_atmu_regs *)(priv->regs_win 7018c2ecf20Sopenharmony_ci + ((i == 0) ? RIO_ATMU_REGS_PORT1_OFFSET : 7028c2ecf20Sopenharmony_ci RIO_ATMU_REGS_PORT2_OFFSET)); 7038c2ecf20Sopenharmony_ci 7048c2ecf20Sopenharmony_ci priv->maint_atmu_regs = priv->atmu_regs + 1; 7058c2ecf20Sopenharmony_ci priv->inb_atmu_regs = (struct rio_inb_atmu_regs __iomem *) 7068c2ecf20Sopenharmony_ci (priv->regs_win + 7078c2ecf20Sopenharmony_ci ((i == 0) ? RIO_INB_ATMU_REGS_PORT1_OFFSET : 7088c2ecf20Sopenharmony_ci RIO_INB_ATMU_REGS_PORT2_OFFSET)); 7098c2ecf20Sopenharmony_ci 7108c2ecf20Sopenharmony_ci /* Set to receive packets with any dest ID */ 7118c2ecf20Sopenharmony_ci out_be32((priv->regs_win + RIO_ISR_AACR + i*0x80), 7128c2ecf20Sopenharmony_ci RIO_ISR_AACR_AA); 7138c2ecf20Sopenharmony_ci 7148c2ecf20Sopenharmony_ci /* Configure maintenance transaction window */ 7158c2ecf20Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowbar, 7168c2ecf20Sopenharmony_ci port->iores.start >> 12); 7178c2ecf20Sopenharmony_ci out_be32(&priv->maint_atmu_regs->rowar, 7188c2ecf20Sopenharmony_ci 0x80077000 | (ilog2(RIO_MAINT_WIN_SIZE) - 1)); 7198c2ecf20Sopenharmony_ci 7208c2ecf20Sopenharmony_ci priv->maint_win = ioremap(port->iores.start, 7218c2ecf20Sopenharmony_ci RIO_MAINT_WIN_SIZE); 7228c2ecf20Sopenharmony_ci 7238c2ecf20Sopenharmony_ci rio_law_start = range_start; 7248c2ecf20Sopenharmony_ci 7258c2ecf20Sopenharmony_ci fsl_rio_setup_rmu(port, rmu_np[i]); 7268c2ecf20Sopenharmony_ci fsl_rio_inbound_mem_init(priv); 7278c2ecf20Sopenharmony_ci 7288c2ecf20Sopenharmony_ci dbell->mport[i] = port; 7298c2ecf20Sopenharmony_ci pw->mport[i] = port; 7308c2ecf20Sopenharmony_ci 7318c2ecf20Sopenharmony_ci if (rio_register_mport(port)) { 7328c2ecf20Sopenharmony_ci release_resource(&port->iores); 7338c2ecf20Sopenharmony_ci kfree(priv); 7348c2ecf20Sopenharmony_ci kfree(port); 7358c2ecf20Sopenharmony_ci continue; 7368c2ecf20Sopenharmony_ci } 7378c2ecf20Sopenharmony_ci active_ports++; 7388c2ecf20Sopenharmony_ci } 7398c2ecf20Sopenharmony_ci 7408c2ecf20Sopenharmony_ci if (!active_ports) { 7418c2ecf20Sopenharmony_ci rc = -ENOLINK; 7428c2ecf20Sopenharmony_ci goto err; 7438c2ecf20Sopenharmony_ci } 7448c2ecf20Sopenharmony_ci 7458c2ecf20Sopenharmony_ci fsl_rio_doorbell_init(dbell); 7468c2ecf20Sopenharmony_ci fsl_rio_port_write_init(pw); 7478c2ecf20Sopenharmony_ci 7488c2ecf20Sopenharmony_ci return 0; 7498c2ecf20Sopenharmony_cierr: 7508c2ecf20Sopenharmony_ci kfree(pw); 7518c2ecf20Sopenharmony_ci pw = NULL; 7528c2ecf20Sopenharmony_cierr_pw: 7538c2ecf20Sopenharmony_ci kfree(dbell); 7548c2ecf20Sopenharmony_ci dbell = NULL; 7558c2ecf20Sopenharmony_cierr_dbell: 7568c2ecf20Sopenharmony_ci iounmap(rmu_regs_win); 7578c2ecf20Sopenharmony_ci rmu_regs_win = NULL; 7588c2ecf20Sopenharmony_cierr_rmu: 7598c2ecf20Sopenharmony_ci kfree(ops); 7608c2ecf20Sopenharmony_cierr_ops: 7618c2ecf20Sopenharmony_ci iounmap(rio_regs_win); 7628c2ecf20Sopenharmony_ci rio_regs_win = NULL; 7638c2ecf20Sopenharmony_cierr_rio_regs: 7648c2ecf20Sopenharmony_ci return rc; 7658c2ecf20Sopenharmony_ci} 7668c2ecf20Sopenharmony_ci 7678c2ecf20Sopenharmony_ci/* The probe function for RapidIO peer-to-peer network. 7688c2ecf20Sopenharmony_ci */ 7698c2ecf20Sopenharmony_cistatic int fsl_of_rio_rpn_probe(struct platform_device *dev) 7708c2ecf20Sopenharmony_ci{ 7718c2ecf20Sopenharmony_ci printk(KERN_INFO "Setting up RapidIO peer-to-peer network %pOF\n", 7728c2ecf20Sopenharmony_ci dev->dev.of_node); 7738c2ecf20Sopenharmony_ci 7748c2ecf20Sopenharmony_ci return fsl_rio_setup(dev); 7758c2ecf20Sopenharmony_ci}; 7768c2ecf20Sopenharmony_ci 7778c2ecf20Sopenharmony_cistatic const struct of_device_id fsl_of_rio_rpn_ids[] = { 7788c2ecf20Sopenharmony_ci { 7798c2ecf20Sopenharmony_ci .compatible = "fsl,srio", 7808c2ecf20Sopenharmony_ci }, 7818c2ecf20Sopenharmony_ci {}, 7828c2ecf20Sopenharmony_ci}; 7838c2ecf20Sopenharmony_ci 7848c2ecf20Sopenharmony_cistatic struct platform_driver fsl_of_rio_rpn_driver = { 7858c2ecf20Sopenharmony_ci .driver = { 7868c2ecf20Sopenharmony_ci .name = "fsl-of-rio", 7878c2ecf20Sopenharmony_ci .of_match_table = fsl_of_rio_rpn_ids, 7888c2ecf20Sopenharmony_ci }, 7898c2ecf20Sopenharmony_ci .probe = fsl_of_rio_rpn_probe, 7908c2ecf20Sopenharmony_ci}; 7918c2ecf20Sopenharmony_ci 7928c2ecf20Sopenharmony_cistatic __init int fsl_of_rio_rpn_init(void) 7938c2ecf20Sopenharmony_ci{ 7948c2ecf20Sopenharmony_ci return platform_driver_register(&fsl_of_rio_rpn_driver); 7958c2ecf20Sopenharmony_ci} 7968c2ecf20Sopenharmony_ci 7978c2ecf20Sopenharmony_cisubsys_initcall(fsl_of_rio_rpn_init); 798