linux/drivers/rapidio/switches/tsi568.c
<<
>>
Prefs
   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 <linux/module.h>
  23#include "../rio.h"
  24
  25/* Global (broadcast) route registers */
  26#define SPBC_ROUTE_CFG_DESTID   0x10070
  27#define SPBC_ROUTE_CFG_PORT     0x10074
  28
  29/* Per port route registers */
  30#define SPP_ROUTE_CFG_DESTID(n) (0x11070 + 0x100*n)
  31#define SPP_ROUTE_CFG_PORT(n)   (0x11074 + 0x100*n)
  32
  33#define TSI568_SP_MODE(n)       (0x11004 + 0x100*n)
  34#define  TSI568_SP_MODE_PW_DIS  0x08000000
  35
  36static int
  37tsi568_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
  38                       u16 table, u16 route_destid, u8 route_port)
  39{
  40        if (table == RIO_GLOBAL_TABLE) {
  41                rio_mport_write_config_32(mport, destid, hopcount,
  42                                        SPBC_ROUTE_CFG_DESTID, route_destid);
  43                rio_mport_write_config_32(mport, destid, hopcount,
  44                                        SPBC_ROUTE_CFG_PORT, route_port);
  45        } else {
  46                rio_mport_write_config_32(mport, destid, hopcount,
  47                                        SPP_ROUTE_CFG_DESTID(table),
  48                                        route_destid);
  49                rio_mport_write_config_32(mport, destid, hopcount,
  50                                        SPP_ROUTE_CFG_PORT(table), route_port);
  51        }
  52
  53        udelay(10);
  54
  55        return 0;
  56}
  57
  58static int
  59tsi568_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
  60                       u16 table, u16 route_destid, u8 *route_port)
  61{
  62        int ret = 0;
  63        u32 result;
  64
  65        if (table == RIO_GLOBAL_TABLE) {
  66                rio_mport_write_config_32(mport, destid, hopcount,
  67                                        SPBC_ROUTE_CFG_DESTID, route_destid);
  68                rio_mport_read_config_32(mport, destid, hopcount,
  69                                        SPBC_ROUTE_CFG_PORT, &result);
  70        } else {
  71                rio_mport_write_config_32(mport, destid, hopcount,
  72                                        SPP_ROUTE_CFG_DESTID(table),
  73                                        route_destid);
  74                rio_mport_read_config_32(mport, destid, hopcount,
  75                                        SPP_ROUTE_CFG_PORT(table), &result);
  76        }
  77
  78        *route_port = result;
  79        if (*route_port > 15)
  80                ret = -1;
  81
  82        return ret;
  83}
  84
  85static int
  86tsi568_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
  87                       u16 table)
  88{
  89        u32 route_idx;
  90        u32 lut_size;
  91
  92        lut_size = (mport->sys_size) ? 0x1ff : 0xff;
  93
  94        if (table == RIO_GLOBAL_TABLE) {
  95                rio_mport_write_config_32(mport, destid, hopcount,
  96                                        SPBC_ROUTE_CFG_DESTID, 0x80000000);
  97                for (route_idx = 0; route_idx <= lut_size; route_idx++)
  98                        rio_mport_write_config_32(mport, destid, hopcount,
  99                                                SPBC_ROUTE_CFG_PORT,
 100                                                RIO_INVALID_ROUTE);
 101        } else {
 102                rio_mport_write_config_32(mport, destid, hopcount,
 103                                        SPP_ROUTE_CFG_DESTID(table),
 104                                        0x80000000);
 105                for (route_idx = 0; route_idx <= lut_size; route_idx++)
 106                        rio_mport_write_config_32(mport, destid, hopcount,
 107                                                SPP_ROUTE_CFG_PORT(table),
 108                                                RIO_INVALID_ROUTE);
 109        }
 110
 111        return 0;
 112}
 113
 114static int
 115tsi568_em_init(struct rio_dev *rdev)
 116{
 117        u32 regval;
 118        int portnum;
 119
 120        pr_debug("TSI568 %s [%d:%d]\n", __func__, rdev->destid, rdev->hopcount);
 121
 122        /* Make sure that Port-Writes are disabled (for all ports) */
 123        for (portnum = 0;
 124             portnum < RIO_GET_TOTAL_PORTS(rdev->swpinfo); portnum++) {
 125                rio_read_config_32(rdev, TSI568_SP_MODE(portnum), &regval);
 126                rio_write_config_32(rdev, TSI568_SP_MODE(portnum),
 127                                    regval | TSI568_SP_MODE_PW_DIS);
 128        }
 129
 130        return 0;
 131}
 132
 133static struct rio_switch_ops tsi568_switch_ops = {
 134        .owner = THIS_MODULE,
 135        .add_entry = tsi568_route_add_entry,
 136        .get_entry = tsi568_route_get_entry,
 137        .clr_table = tsi568_route_clr_table,
 138        .set_domain = NULL,
 139        .get_domain = NULL,
 140        .em_init = tsi568_em_init,
 141        .em_handle = NULL,
 142};
 143
 144static int tsi568_probe(struct rio_dev *rdev, const struct rio_device_id *id)
 145{
 146        pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
 147
 148        spin_lock(&rdev->rswitch->lock);
 149
 150        if (rdev->rswitch->ops) {
 151                spin_unlock(&rdev->rswitch->lock);
 152                return -EINVAL;
 153        }
 154
 155        rdev->rswitch->ops = &tsi568_switch_ops;
 156        spin_unlock(&rdev->rswitch->lock);
 157        return 0;
 158}
 159
 160static void tsi568_remove(struct rio_dev *rdev)
 161{
 162        pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
 163        spin_lock(&rdev->rswitch->lock);
 164        if (rdev->rswitch->ops != &tsi568_switch_ops) {
 165                spin_unlock(&rdev->rswitch->lock);
 166                return;
 167        }
 168        rdev->rswitch->ops = NULL;
 169        spin_unlock(&rdev->rswitch->lock);
 170}
 171
 172static struct rio_device_id tsi568_id_table[] = {
 173        {RIO_DEVICE(RIO_DID_TSI568, RIO_VID_TUNDRA)},
 174        { 0, }  /* terminate list */
 175};
 176
 177static struct rio_driver tsi568_driver = {
 178        .name = "tsi568",
 179        .id_table = tsi568_id_table,
 180        .probe = tsi568_probe,
 181        .remove = tsi568_remove,
 182};
 183
 184static int __init tsi568_init(void)
 185{
 186        return rio_register_driver(&tsi568_driver);
 187}
 188
 189static void __exit tsi568_exit(void)
 190{
 191        rio_unregister_driver(&tsi568_driver);
 192}
 193
 194device_initcall(tsi568_init);
 195module_exit(tsi568_exit);
 196
 197MODULE_DESCRIPTION("IDT Tsi568 Serial RapidIO switch driver");
 198MODULE_AUTHOR("Integrated Device Technology, Inc.");
 199MODULE_LICENSE("GPL");
 200