^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 1) // SPDX-License-Identifier: GPL-2.0-or-later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 3) * IDT CPS RapidIO switches support
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 4) *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 5) * Copyright 2009-2010 Integrated Device Technology, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 6) * Alexandre Bounine <alexandre.bounine@idt.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 7) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 8)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 9) #include <linux/rio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 10) #include <linux/rio_drv.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 11) #include <linux/rio_ids.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 12) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 13) #include "../rio.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 14)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 15) #define CPS_DEFAULT_ROUTE 0xde
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 16) #define CPS_NO_ROUTE 0xdf
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 17)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 18) #define IDTCPS_RIO_DOMAIN 0xf20020
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 19)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 20) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 21) idtcps_route_add_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 22) u16 table, u16 route_destid, u8 route_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 23) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 24) u32 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 25)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 26) if (route_port == RIO_INVALID_ROUTE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 27) route_port = CPS_DEFAULT_ROUTE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 28)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 29) if (table == RIO_GLOBAL_TABLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 30) rio_mport_write_config_32(mport, destid, hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 31) RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 32)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 33) rio_mport_read_config_32(mport, destid, hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 34) RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 35)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 36) result = (0xffffff00 & result) | (u32)route_port;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 37) rio_mport_write_config_32(mport, destid, hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 38) RIO_STD_RTE_CONF_PORT_SEL_CSR, result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 39) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 40)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 41) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 43)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 44) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 45) idtcps_route_get_entry(struct rio_mport *mport, u16 destid, u8 hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 46) u16 table, u16 route_destid, u8 *route_port)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 47) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 48) u32 result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 49)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 50) if (table == RIO_GLOBAL_TABLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 51) rio_mport_write_config_32(mport, destid, hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 52) RIO_STD_RTE_CONF_DESTID_SEL_CSR, route_destid);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 53)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 54) rio_mport_read_config_32(mport, destid, hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 55) RIO_STD_RTE_CONF_PORT_SEL_CSR, &result);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 56)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 57) if (CPS_DEFAULT_ROUTE == (u8)result ||
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 58) CPS_NO_ROUTE == (u8)result)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 59) *route_port = RIO_INVALID_ROUTE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 60) else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 61) *route_port = (u8)result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 62) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 63)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 64) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 65) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 66)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 67) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 68) idtcps_route_clr_table(struct rio_mport *mport, u16 destid, u8 hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 69) u16 table)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 70) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 71) u32 i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 72)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 73) if (table == RIO_GLOBAL_TABLE) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 74) for (i = 0x80000000; i <= 0x800000ff;) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 75) rio_mport_write_config_32(mport, destid, hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 76) RIO_STD_RTE_CONF_DESTID_SEL_CSR, i);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 77) rio_mport_write_config_32(mport, destid, hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 78) RIO_STD_RTE_CONF_PORT_SEL_CSR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 79) (CPS_DEFAULT_ROUTE << 24) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 80) (CPS_DEFAULT_ROUTE << 16) |
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 81) (CPS_DEFAULT_ROUTE << 8) | CPS_DEFAULT_ROUTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 82) i += 4;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 83) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 84) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 85)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 86) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 87) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 88)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 89) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 90) idtcps_set_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 91) u8 sw_domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 92) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 93) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 94) * Switch domain configuration operates only at global level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 95) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 96) rio_mport_write_config_32(mport, destid, hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 97) IDTCPS_RIO_DOMAIN, (u32)sw_domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 98) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 99) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) static int
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) idtcps_get_domain(struct rio_mport *mport, u16 destid, u8 hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) u8 *sw_domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) u32 regval;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) * Switch domain configuration operates only at global level
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) rio_mport_read_config_32(mport, destid, hopcount,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) IDTCPS_RIO_DOMAIN, ®val);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) *sw_domain = (u8)(regval & 0xff);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) static struct rio_switch_ops idtcps_switch_ops = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) .owner = THIS_MODULE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) .add_entry = idtcps_route_add_entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) .get_entry = idtcps_route_get_entry,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) .clr_table = idtcps_route_clr_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) .set_domain = idtcps_set_domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) .get_domain = idtcps_get_domain,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) .em_init = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) .em_handle = NULL,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) static int idtcps_probe(struct rio_dev *rdev, const struct rio_device_id *id)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) spin_lock(&rdev->rswitch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) if (rdev->rswitch->ops) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) spin_unlock(&rdev->rswitch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) return -EINVAL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) rdev->rswitch->ops = &idtcps_switch_ops;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) if (rdev->do_enum) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) /* set TVAL = ~50us */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) rio_write_config_32(rdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) rdev->phys_efptr + RIO_PORT_LINKTO_CTL_CSR, 0x8e << 8);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) /* Ensure that default routing is disabled on startup */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) rio_write_config_32(rdev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) RIO_STD_RTE_DEFAULT_PORT, CPS_NO_ROUTE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) spin_unlock(&rdev->rswitch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) static void idtcps_remove(struct rio_dev *rdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) pr_debug("RIO: %s for %s\n", __func__, rio_name(rdev));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) spin_lock(&rdev->rswitch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) if (rdev->rswitch->ops != &idtcps_switch_ops) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) spin_unlock(&rdev->rswitch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) return;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) rdev->rswitch->ops = NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) spin_unlock(&rdev->rswitch->lock);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static const struct rio_device_id idtcps_id_table[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) {RIO_DEVICE(RIO_DID_IDTCPS6Q, RIO_VID_IDT)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) {RIO_DEVICE(RIO_DID_IDTCPS8, RIO_VID_IDT)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) {RIO_DEVICE(RIO_DID_IDTCPS10Q, RIO_VID_IDT)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) {RIO_DEVICE(RIO_DID_IDTCPS12, RIO_VID_IDT)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) {RIO_DEVICE(RIO_DID_IDTCPS16, RIO_VID_IDT)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) {RIO_DEVICE(RIO_DID_IDT70K200, RIO_VID_IDT)},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) { 0, } /* terminate list */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) static struct rio_driver idtcps_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) .name = "idtcps",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) .id_table = idtcps_id_table,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) .probe = idtcps_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) .remove = idtcps_remove,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) static int __init idtcps_init(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) return rio_register_driver(&idtcps_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) static void __exit idtcps_exit(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) rio_unregister_driver(&idtcps_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) device_initcall(idtcps_init);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) module_exit(idtcps_exit);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) MODULE_DESCRIPTION("IDT CPS Gen.1 Serial RapidIO switch family driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) MODULE_AUTHOR("Integrated Device Technology, Inc.");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) MODULE_LICENSE("GPL");