162306a36Sopenharmony_ci// SPDX-License-Identifier: (GPL-2.0 OR MIT) 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Microsemi Ocelot Switch driver 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Copyright (c) 2017 Microsemi Corporation 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci#include <linux/io.h> 862306a36Sopenharmony_ci#include <linux/kernel.h> 962306a36Sopenharmony_ci#include <linux/platform_device.h> 1062306a36Sopenharmony_ci 1162306a36Sopenharmony_ci#include "ocelot.h" 1262306a36Sopenharmony_ci 1362306a36Sopenharmony_ciint __ocelot_bulk_read_ix(struct ocelot *ocelot, enum ocelot_reg reg, 1462306a36Sopenharmony_ci u32 offset, void *buf, int count) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci enum ocelot_target target; 1762306a36Sopenharmony_ci u32 addr; 1862306a36Sopenharmony_ci 1962306a36Sopenharmony_ci ocelot_reg_to_target_addr(ocelot, reg, &target, &addr); 2062306a36Sopenharmony_ci WARN_ON(!target); 2162306a36Sopenharmony_ci 2262306a36Sopenharmony_ci return regmap_bulk_read(ocelot->targets[target], addr + offset, 2362306a36Sopenharmony_ci buf, count); 2462306a36Sopenharmony_ci} 2562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__ocelot_bulk_read_ix); 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ciu32 __ocelot_read_ix(struct ocelot *ocelot, enum ocelot_reg reg, u32 offset) 2862306a36Sopenharmony_ci{ 2962306a36Sopenharmony_ci enum ocelot_target target; 3062306a36Sopenharmony_ci u32 addr, val; 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci ocelot_reg_to_target_addr(ocelot, reg, &target, &addr); 3362306a36Sopenharmony_ci WARN_ON(!target); 3462306a36Sopenharmony_ci 3562306a36Sopenharmony_ci regmap_read(ocelot->targets[target], addr + offset, &val); 3662306a36Sopenharmony_ci return val; 3762306a36Sopenharmony_ci} 3862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__ocelot_read_ix); 3962306a36Sopenharmony_ci 4062306a36Sopenharmony_civoid __ocelot_write_ix(struct ocelot *ocelot, u32 val, enum ocelot_reg reg, 4162306a36Sopenharmony_ci u32 offset) 4262306a36Sopenharmony_ci{ 4362306a36Sopenharmony_ci enum ocelot_target target; 4462306a36Sopenharmony_ci u32 addr; 4562306a36Sopenharmony_ci 4662306a36Sopenharmony_ci ocelot_reg_to_target_addr(ocelot, reg, &target, &addr); 4762306a36Sopenharmony_ci WARN_ON(!target); 4862306a36Sopenharmony_ci 4962306a36Sopenharmony_ci regmap_write(ocelot->targets[target], addr + offset, val); 5062306a36Sopenharmony_ci} 5162306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__ocelot_write_ix); 5262306a36Sopenharmony_ci 5362306a36Sopenharmony_civoid __ocelot_rmw_ix(struct ocelot *ocelot, u32 val, u32 mask, 5462306a36Sopenharmony_ci enum ocelot_reg reg, u32 offset) 5562306a36Sopenharmony_ci{ 5662306a36Sopenharmony_ci enum ocelot_target target; 5762306a36Sopenharmony_ci u32 addr; 5862306a36Sopenharmony_ci 5962306a36Sopenharmony_ci ocelot_reg_to_target_addr(ocelot, reg, &target, &addr); 6062306a36Sopenharmony_ci WARN_ON(!target); 6162306a36Sopenharmony_ci 6262306a36Sopenharmony_ci regmap_update_bits(ocelot->targets[target], addr + offset, mask, val); 6362306a36Sopenharmony_ci} 6462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__ocelot_rmw_ix); 6562306a36Sopenharmony_ci 6662306a36Sopenharmony_ciu32 ocelot_port_readl(struct ocelot_port *port, enum ocelot_reg reg) 6762306a36Sopenharmony_ci{ 6862306a36Sopenharmony_ci struct ocelot *ocelot = port->ocelot; 6962306a36Sopenharmony_ci u16 target = reg >> TARGET_OFFSET; 7062306a36Sopenharmony_ci u32 val; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci WARN_ON(!target); 7362306a36Sopenharmony_ci 7462306a36Sopenharmony_ci regmap_read(port->target, ocelot->map[target][reg & REG_MASK], &val); 7562306a36Sopenharmony_ci return val; 7662306a36Sopenharmony_ci} 7762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_readl); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_civoid ocelot_port_writel(struct ocelot_port *port, u32 val, enum ocelot_reg reg) 8062306a36Sopenharmony_ci{ 8162306a36Sopenharmony_ci struct ocelot *ocelot = port->ocelot; 8262306a36Sopenharmony_ci u16 target = reg >> TARGET_OFFSET; 8362306a36Sopenharmony_ci 8462306a36Sopenharmony_ci WARN_ON(!target); 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci regmap_write(port->target, ocelot->map[target][reg & REG_MASK], val); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_writel); 8962306a36Sopenharmony_ci 9062306a36Sopenharmony_civoid ocelot_port_rmwl(struct ocelot_port *port, u32 val, u32 mask, 9162306a36Sopenharmony_ci enum ocelot_reg reg) 9262306a36Sopenharmony_ci{ 9362306a36Sopenharmony_ci u32 cur = ocelot_port_readl(port, reg); 9462306a36Sopenharmony_ci 9562306a36Sopenharmony_ci ocelot_port_writel(port, (cur & (~mask)) | val, reg); 9662306a36Sopenharmony_ci} 9762306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_port_rmwl); 9862306a36Sopenharmony_ci 9962306a36Sopenharmony_ciu32 __ocelot_target_read_ix(struct ocelot *ocelot, enum ocelot_target target, 10062306a36Sopenharmony_ci u32 reg, u32 offset) 10162306a36Sopenharmony_ci{ 10262306a36Sopenharmony_ci u32 val; 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci regmap_read(ocelot->targets[target], 10562306a36Sopenharmony_ci ocelot->map[target][reg] + offset, &val); 10662306a36Sopenharmony_ci return val; 10762306a36Sopenharmony_ci} 10862306a36Sopenharmony_ci 10962306a36Sopenharmony_civoid __ocelot_target_write_ix(struct ocelot *ocelot, enum ocelot_target target, 11062306a36Sopenharmony_ci u32 val, u32 reg, u32 offset) 11162306a36Sopenharmony_ci{ 11262306a36Sopenharmony_ci regmap_write(ocelot->targets[target], 11362306a36Sopenharmony_ci ocelot->map[target][reg] + offset, val); 11462306a36Sopenharmony_ci} 11562306a36Sopenharmony_ci 11662306a36Sopenharmony_ciint ocelot_regfields_init(struct ocelot *ocelot, 11762306a36Sopenharmony_ci const struct reg_field *const regfields) 11862306a36Sopenharmony_ci{ 11962306a36Sopenharmony_ci unsigned int i; 12062306a36Sopenharmony_ci u16 target; 12162306a36Sopenharmony_ci 12262306a36Sopenharmony_ci for (i = 0; i < REGFIELD_MAX; i++) { 12362306a36Sopenharmony_ci struct reg_field regfield = {}; 12462306a36Sopenharmony_ci u32 reg = regfields[i].reg; 12562306a36Sopenharmony_ci 12662306a36Sopenharmony_ci if (!reg) 12762306a36Sopenharmony_ci continue; 12862306a36Sopenharmony_ci 12962306a36Sopenharmony_ci target = regfields[i].reg >> TARGET_OFFSET; 13062306a36Sopenharmony_ci 13162306a36Sopenharmony_ci regfield.reg = ocelot->map[target][reg & REG_MASK]; 13262306a36Sopenharmony_ci regfield.lsb = regfields[i].lsb; 13362306a36Sopenharmony_ci regfield.msb = regfields[i].msb; 13462306a36Sopenharmony_ci regfield.id_size = regfields[i].id_size; 13562306a36Sopenharmony_ci regfield.id_offset = regfields[i].id_offset; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci ocelot->regfields[i] = 13862306a36Sopenharmony_ci devm_regmap_field_alloc(ocelot->dev, 13962306a36Sopenharmony_ci ocelot->targets[target], 14062306a36Sopenharmony_ci regfield); 14162306a36Sopenharmony_ci 14262306a36Sopenharmony_ci if (IS_ERR(ocelot->regfields[i])) 14362306a36Sopenharmony_ci return PTR_ERR(ocelot->regfields[i]); 14462306a36Sopenharmony_ci } 14562306a36Sopenharmony_ci 14662306a36Sopenharmony_ci return 0; 14762306a36Sopenharmony_ci} 14862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_regfields_init); 14962306a36Sopenharmony_ci 15062306a36Sopenharmony_cistatic struct regmap_config ocelot_regmap_config = { 15162306a36Sopenharmony_ci .reg_bits = 32, 15262306a36Sopenharmony_ci .val_bits = 32, 15362306a36Sopenharmony_ci .reg_stride = 4, 15462306a36Sopenharmony_ci}; 15562306a36Sopenharmony_ci 15662306a36Sopenharmony_cistruct regmap *ocelot_regmap_init(struct ocelot *ocelot, struct resource *res) 15762306a36Sopenharmony_ci{ 15862306a36Sopenharmony_ci void __iomem *regs; 15962306a36Sopenharmony_ci 16062306a36Sopenharmony_ci regs = devm_ioremap_resource(ocelot->dev, res); 16162306a36Sopenharmony_ci if (IS_ERR(regs)) 16262306a36Sopenharmony_ci return ERR_CAST(regs); 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci ocelot_regmap_config.name = res->name; 16562306a36Sopenharmony_ci 16662306a36Sopenharmony_ci return devm_regmap_init_mmio(ocelot->dev, regs, &ocelot_regmap_config); 16762306a36Sopenharmony_ci} 16862306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(ocelot_regmap_init); 169