1/* 2 * RapidIO Tsi568 switch support 3 * 4 * Copyright 2009-2010 Integrated Device Technology, Inc. 5 * Alexandre Bounine <alexandre.bounine@idt.com> 6 * - Added EM support 7 * - Modified switch operations initialization. 8 * 9 * Copyright 2005 MontaVista Software, Inc. 10 * Matt Porter <mporter@kernel.crashing.org> 11 * 12 * This program is free software; you can redistribute it and/or modify it 13 * under the terms of the GNU General Public License as published by the 14 * Free Software Foundation; either version 2 of the License, or (at your 15 * option) any later version. 16 */ 17 18#include <linux/rio.h> 19#include <linux/rio_drv.h> 20#include <linux/rio_ids.h> 21#include <linux/delay.h> 22#include "../rio.h" 23 24/* Global (broadcast) route registers */ 25#define SPBC_ROUTE_CFG_DESTID 0x10070 26#define SPBC_ROUTE_CFG_PORT 0x10074 27 28/* Per port route registers */ 29#define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n) 30#define SPP_ROUTE_CFG_PORT(n) (0x11074 + 0x100*n) 31 32#define TSI568_SP_MODE_BC 0x10004 33#define TSI568_SP_MODE_PW_DIS 0x08000000 34 35static int 36tsi568_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 37 u16 table, u16 route_destid, u8 route_port) 38{ 39 if (table == RIO_GLOBAL_TABLE) { 40 rio_mport_write_config_32(mport, destid, hopcount, 41 SPBC_ROUTE_CFG_DESTID, route_destid); 42 rio_mport_write_config_32(mport, destid, hopcount, 43 SPBC_ROUTE_CFG_PORT, route_port); 44 } else { 45 rio_mport_write_config_32(mport, destid, hopcount, 46 SPP_ROUTE_CFG_DESTID(table), 47 route_destid); 48 rio_mport_write_config_32(mport, destid, hopcount, 49 SPP_ROUTE_CFG_PORT(table), route_port); 50 } 51 52 udelay(10); 53 54 return 0; 55} 56 57static int 58tsi568_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount, 59 u16 table, u16 route_destid, u8 *route_port) 60{ 61 int ret = 0; 62 u32 result; 63 64 if (table == RIO_GLOBAL_TABLE) { 65 rio_mport_write_config_32(mport, destid, hopcount, 66 SPBC_ROUTE_CFG_DESTID, route_destid); 67 rio_mport_read_config_32(mport, destid, hopcount, 68 SPBC_ROUTE_CFG_PORT, &result); 69 } else { 70 rio_mport_write_config_32(mport, destid, hopcount, 71 SPP_ROUTE_CFG_DESTID(table), 72 route_destid); 73 rio_mport_read_config_32(mport, destid, hopcount, 74 SPP_ROUTE_CFG_PORT(table), &result); 75 } 76 77 *route_port = result; 78 if (*route_port > 15) 79 ret = -1; 80 81 return ret; 82} 83 84static int 85tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount, 86 u16 table) 87{ 88 u32 route_idx; 89 u32 lut_size; 90 91 lut_size = (mport->sys_size) ? 0x1ff : 0xff; 92 93 if (table == RIO_GLOBAL_TABLE) { 94 rio_mport_write_config_32(mport, destid, hopcount, 95 SPBC_ROUTE_CFG_DESTID, 0x80000000); 96 for (route_idx = 0; route_idx <= lut_size; route_idx++) 97 rio_mport_write_config_32(mport, destid, hopcount, 98 SPBC_ROUTE_CFG_PORT, 99 RIO_INVALID_ROUTE); 100 } else { 101 rio_mport_write_config_32(mport, destid, hopcount, 102 SPP_ROUTE_CFG_DESTID(table), 103 0x80000000); 104 for (route_idx = 0; route_idx <= lut_size; route_idx++) 105 rio_mport_write_config_32(mport, destid, hopcount, 106 SPP_ROUTE_CFG_PORT(table), 107 RIO_INVALID_ROUTE); 108 } 109 110 return 0; 111} 112 113static int 114tsi568_em_init(struct rio_dev *rdev) 115{ 116 struct rio_mport *mport = rdev->net->hport; 117 u16 destid = rdev->rswitch->destid; 118 u8 hopcount = rdev->rswitch->hopcount; 119 u32 regval; 120 121 pr_debug("TSI568 %s [%d:%d]\n", __func__, destid, hopcount); 122 123 /* Make sure that Port-Writes are disabled (for all ports) */ 124 rio_mport_read_config_32(mport, destid, hopcount, 125 TSI568_SP_MODE_BC, ®val); 126 rio_mport_write_config_32(mport, destid, hopcount, 127 TSI568_SP_MODE_BC, regval | TSI568_SP_MODE_PW_DIS); 128 129 return 0; 130} 131 132static int tsi568_switch_init(struct rio_dev *rdev, int do_enum) 133{ 134 pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev)); 135 rdev->rswitch->add_entry = tsi568_route_add_entry; 136 rdev->rswitch->get_entry = tsi568_route_get_entry; 137 rdev->rswitch->clr_table = tsi568_route_clr_table; 138 rdev->rswitch->set_domain = NULL; 139 rdev->rswitch->get_domain = NULL; 140 rdev->rswitch->em_init = tsi568_em_init; 141 rdev->rswitch->em_handle = NULL; 142 143 return 0; 144} 145 146DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_switch_init); 147