1 // SPDX-License-Identifier: (GPL-2.0 OR MIT) 2 /* 3 * Microsemi Ocelot Switch driver 4 * 5 * Copyright (c) 2017 Microsemi Corporation 6 */ 7 #include <linux/io.h> 8 #include <linux/kernel.h> 9 #include <linux/platform_device.h> 10 11 #include "ocelot.h" 12 13 u32 __ocelot_read_ix(struct ocelot *ocelot, u32 reg, u32 offset) 14 { 15 u16 target = reg >> TARGET_OFFSET; 16 u32 val; 17 18 WARN_ON(!target); 19 20 regmap_read(ocelot->targets[target], 21 ocelot->map[target][reg & REG_MASK] + offset, &val); 22 return val; 23 } 24 EXPORT_SYMBOL(__ocelot_read_ix); 25 26 void __ocelot_write_ix(struct ocelot *ocelot, u32 val, u32 reg, u32 offset) 27 { 28 u16 target = reg >> TARGET_OFFSET; 29 30 WARN_ON(!target); 31 32 regmap_write(ocelot->targets[target], 33 ocelot->map[target][reg & REG_MASK] + offset, val); 34 } 35 EXPORT_SYMBOL(__ocelot_write_ix); 36 37 void __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, u32 reg, 38 u32 offset) 39 { 40 u16 target = reg >> TARGET_OFFSET; 41 42 WARN_ON(!target); 43 44 regmap_update_bits(ocelot->targets[target], 45 ocelot->map[target][reg & REG_MASK] + offset, 46 mask, val); 47 } 48 EXPORT_SYMBOL(__ocelot_rmw_ix); 49 50 u32 ocelot_port_readl(struct ocelot_port *port, u32 reg) 51 { 52 struct ocelot *ocelot = port->ocelot; 53 u16 target = reg >> TARGET_OFFSET; 54 u32 val; 55 56 WARN_ON(!target); 57 58 regmap_read(port->target, ocelot->map[target][reg & REG_MASK], &val); 59 return val; 60 } 61 EXPORT_SYMBOL(ocelot_port_readl); 62 63 void ocelot_port_writel(struct ocelot_port *port, u32 val, u32 reg) 64 { 65 struct ocelot *ocelot = port->ocelot; 66 u16 target = reg >> TARGET_OFFSET; 67 68 WARN_ON(!target); 69 70 regmap_write(port->target, ocelot->map[target][reg & REG_MASK], val); 71 } 72 EXPORT_SYMBOL(ocelot_port_writel); 73 74 void ocelot_port_rmwl(struct ocelot_port *port, u32 val, u32 mask, u32 reg) 75 { 76 u32 cur = ocelot_port_readl(port, reg); 77 78 ocelot_port_writel(port, (cur & (~mask)) | val, reg); 79 } 80 EXPORT_SYMBOL(ocelot_port_rmwl); 81 82 u32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target, 83 u32 reg, u32 offset) 84 { 85 u32 val; 86 87 regmap_read(ocelot->targets[target], 88 ocelot->map[target][reg] + offset, &val); 89 return val; 90 } 91 92 void __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target, 93 u32 val, u32 reg, u32 offset) 94 { 95 regmap_write(ocelot->targets[target], 96 ocelot->map[target][reg] + offset, val); 97 } 98 99 int ocelot_regfields_init(struct ocelot *ocelot, 100 const struct reg_field *const regfields) 101 { 102 unsigned int i; 103 u16 target; 104 105 for (i = 0; i < REGFIELD_MAX; i++) { 106 struct reg_field regfield = {}; 107 u32 reg = regfields[i].reg; 108 109 if (!reg) 110 continue; 111 112 target = regfields[i].reg >> TARGET_OFFSET; 113 114 regfield.reg = ocelot->map[target][reg & REG_MASK]; 115 regfield.lsb = regfields[i].lsb; 116 regfield.msb = regfields[i].msb; 117 regfield.id_size = regfields[i].id_size; 118 regfield.id_offset = regfields[i].id_offset; 119 120 ocelot->regfields[i] = 121 devm_regmap_field_alloc(ocelot->dev, 122 ocelot->targets[target], 123 regfield); 124 125 if (IS_ERR(ocelot->regfields[i])) 126 return PTR_ERR(ocelot->regfields[i]); 127 } 128 129 return 0; 130 } 131 EXPORT_SYMBOL(ocelot_regfields_init); 132 133 static struct regmap_config ocelot_regmap_config = { 134 .reg_bits = 32, 135 .val_bits = 32, 136 .reg_stride = 4, 137 }; 138 139 struct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res) 140 { 141 void __iomem *regs; 142 143 regs = devm_ioremap_resource(ocelot->dev, res); 144 if (IS_ERR(regs)) 145 return ERR_CAST(regs); 146 147 ocelot_regmap_config.name = res->name; 148 149 return devm_regmap_init_mmio(ocelot->dev, regs, &ocelot_regmap_config); 150 } 151 EXPORT_SYMBOL(ocelot_regmap_init); 152