322840d438321df07bfbd7edce02473f5da8916c
[profile/ivi/kernel-x86-ivi.git] / drivers / rapidio / switches / tsi568.c
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
35 static int
36 tsi568_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
57 static int
58 tsi568_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
84 static int
85 tsi568_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
113 static int
114 tsi568_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, &regval);
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
132 static 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->em_init = tsi568_em_init;
139         rdev->rswitch->em_handle = NULL;
140
141         return 0;
142 }
143
144 DECLARE_RIO_SWITCH_INIT(RIO_VID_TUNDRA, RIO_DID_TSI568, tsi568_switch_init);