1*f0e53aadSHeikki Krogerus // SPDX-License-Identifier: GPL-2.0 OR MIT 2*f0e53aadSHeikki Krogerus /* 3*f0e53aadSHeikki Krogerus * Intel Xe I2C attached Microcontroller Units (MCU) 4*f0e53aadSHeikki Krogerus * 5*f0e53aadSHeikki Krogerus * Copyright (C) 2025 Intel Corporation. 6*f0e53aadSHeikki Krogerus */ 7*f0e53aadSHeikki Krogerus 8*f0e53aadSHeikki Krogerus #include <linux/array_size.h> 9*f0e53aadSHeikki Krogerus #include <linux/container_of.h> 10*f0e53aadSHeikki Krogerus #include <linux/device.h> 11*f0e53aadSHeikki Krogerus #include <linux/err.h> 12*f0e53aadSHeikki Krogerus #include <linux/i2c.h> 13*f0e53aadSHeikki Krogerus #include <linux/ioport.h> 14*f0e53aadSHeikki Krogerus #include <linux/irq.h> 15*f0e53aadSHeikki Krogerus #include <linux/irqdomain.h> 16*f0e53aadSHeikki Krogerus #include <linux/notifier.h> 17*f0e53aadSHeikki Krogerus #include <linux/pci.h> 18*f0e53aadSHeikki Krogerus #include <linux/platform_device.h> 19*f0e53aadSHeikki Krogerus #include <linux/property.h> 20*f0e53aadSHeikki Krogerus #include <linux/regmap.h> 21*f0e53aadSHeikki Krogerus #include <linux/sprintf.h> 22*f0e53aadSHeikki Krogerus #include <linux/string.h> 23*f0e53aadSHeikki Krogerus #include <linux/types.h> 24*f0e53aadSHeikki Krogerus #include <linux/workqueue.h> 25*f0e53aadSHeikki Krogerus 26*f0e53aadSHeikki Krogerus #include "regs/xe_i2c_regs.h" 27*f0e53aadSHeikki Krogerus #include "regs/xe_irq_regs.h" 28*f0e53aadSHeikki Krogerus 29*f0e53aadSHeikki Krogerus #include "xe_device.h" 30*f0e53aadSHeikki Krogerus #include "xe_device_types.h" 31*f0e53aadSHeikki Krogerus #include "xe_i2c.h" 32*f0e53aadSHeikki Krogerus #include "xe_mmio.h" 33*f0e53aadSHeikki Krogerus #include "xe_platform_types.h" 34*f0e53aadSHeikki Krogerus 35*f0e53aadSHeikki Krogerus /** 36*f0e53aadSHeikki Krogerus * DOC: Xe I2C devices 37*f0e53aadSHeikki Krogerus * 38*f0e53aadSHeikki Krogerus * Register a platform device for the I2C host controller (Synpsys DesignWare 39*f0e53aadSHeikki Krogerus * I2C) if the registers of that controller are mapped to the MMIO, and also the 40*f0e53aadSHeikki Krogerus * I2C client device for the Add-In Management Controller (the MCU) attached to 41*f0e53aadSHeikki Krogerus * the host controller. 42*f0e53aadSHeikki Krogerus * 43*f0e53aadSHeikki Krogerus * See drivers/i2c/busses/i2c-designware-* for more information on the I2C host 44*f0e53aadSHeikki Krogerus * controller. 45*f0e53aadSHeikki Krogerus */ 46*f0e53aadSHeikki Krogerus 47*f0e53aadSHeikki Krogerus static const char adapter_name[] = "i2c_designware"; 48*f0e53aadSHeikki Krogerus 49*f0e53aadSHeikki Krogerus static const struct property_entry xe_i2c_adapter_properties[] = { 50*f0e53aadSHeikki Krogerus PROPERTY_ENTRY_STRING("compatible", "intel,xe-i2c"), 51*f0e53aadSHeikki Krogerus PROPERTY_ENTRY_U32("clock-frequency", I2C_MAX_FAST_MODE_PLUS_FREQ), 52*f0e53aadSHeikki Krogerus { } 53*f0e53aadSHeikki Krogerus }; 54*f0e53aadSHeikki Krogerus 55*f0e53aadSHeikki Krogerus static inline void xe_i2c_read_endpoint(struct xe_mmio *mmio, void *ep) 56*f0e53aadSHeikki Krogerus { 57*f0e53aadSHeikki Krogerus u32 *val = ep; 58*f0e53aadSHeikki Krogerus 59*f0e53aadSHeikki Krogerus val[0] = xe_mmio_read32(mmio, REG_SG_REMAP_ADDR_PREFIX); 60*f0e53aadSHeikki Krogerus val[1] = xe_mmio_read32(mmio, REG_SG_REMAP_ADDR_POSTFIX); 61*f0e53aadSHeikki Krogerus } 62*f0e53aadSHeikki Krogerus 63*f0e53aadSHeikki Krogerus static void xe_i2c_client_work(struct work_struct *work) 64*f0e53aadSHeikki Krogerus { 65*f0e53aadSHeikki Krogerus struct xe_i2c *i2c = container_of(work, struct xe_i2c, work); 66*f0e53aadSHeikki Krogerus struct i2c_board_info info = { 67*f0e53aadSHeikki Krogerus .type = "amc", 68*f0e53aadSHeikki Krogerus .flags = I2C_CLIENT_HOST_NOTIFY, 69*f0e53aadSHeikki Krogerus .addr = i2c->ep.addr[1], 70*f0e53aadSHeikki Krogerus }; 71*f0e53aadSHeikki Krogerus 72*f0e53aadSHeikki Krogerus i2c->client[0] = i2c_new_client_device(i2c->adapter, &info); 73*f0e53aadSHeikki Krogerus } 74*f0e53aadSHeikki Krogerus 75*f0e53aadSHeikki Krogerus static int xe_i2c_notifier(struct notifier_block *nb, unsigned long action, void *data) 76*f0e53aadSHeikki Krogerus { 77*f0e53aadSHeikki Krogerus struct xe_i2c *i2c = container_of(nb, struct xe_i2c, bus_notifier); 78*f0e53aadSHeikki Krogerus struct i2c_adapter *adapter = i2c_verify_adapter(data); 79*f0e53aadSHeikki Krogerus struct device *dev = data; 80*f0e53aadSHeikki Krogerus 81*f0e53aadSHeikki Krogerus if (action == BUS_NOTIFY_ADD_DEVICE && 82*f0e53aadSHeikki Krogerus adapter && dev->parent == &i2c->pdev->dev) { 83*f0e53aadSHeikki Krogerus i2c->adapter = adapter; 84*f0e53aadSHeikki Krogerus schedule_work(&i2c->work); 85*f0e53aadSHeikki Krogerus return NOTIFY_OK; 86*f0e53aadSHeikki Krogerus } 87*f0e53aadSHeikki Krogerus 88*f0e53aadSHeikki Krogerus return NOTIFY_DONE; 89*f0e53aadSHeikki Krogerus } 90*f0e53aadSHeikki Krogerus 91*f0e53aadSHeikki Krogerus static int xe_i2c_register_adapter(struct xe_i2c *i2c) 92*f0e53aadSHeikki Krogerus { 93*f0e53aadSHeikki Krogerus struct pci_dev *pci = to_pci_dev(i2c->drm_dev); 94*f0e53aadSHeikki Krogerus struct platform_device *pdev; 95*f0e53aadSHeikki Krogerus struct fwnode_handle *fwnode; 96*f0e53aadSHeikki Krogerus int ret; 97*f0e53aadSHeikki Krogerus 98*f0e53aadSHeikki Krogerus fwnode = fwnode_create_software_node(xe_i2c_adapter_properties, NULL); 99*f0e53aadSHeikki Krogerus if (!fwnode) 100*f0e53aadSHeikki Krogerus return -ENOMEM; 101*f0e53aadSHeikki Krogerus 102*f0e53aadSHeikki Krogerus /* 103*f0e53aadSHeikki Krogerus * Not using platform_device_register_full() here because we don't have 104*f0e53aadSHeikki Krogerus * a handle to the platform_device before it returns. xe_i2c_notifier() 105*f0e53aadSHeikki Krogerus * uses that handle, but it may be called before 106*f0e53aadSHeikki Krogerus * platform_device_register_full() is done. 107*f0e53aadSHeikki Krogerus */ 108*f0e53aadSHeikki Krogerus pdev = platform_device_alloc(adapter_name, pci_dev_id(pci)); 109*f0e53aadSHeikki Krogerus if (!pdev) { 110*f0e53aadSHeikki Krogerus ret = -ENOMEM; 111*f0e53aadSHeikki Krogerus goto err_fwnode_remove; 112*f0e53aadSHeikki Krogerus } 113*f0e53aadSHeikki Krogerus 114*f0e53aadSHeikki Krogerus if (i2c->adapter_irq) { 115*f0e53aadSHeikki Krogerus struct resource res; 116*f0e53aadSHeikki Krogerus 117*f0e53aadSHeikki Krogerus res = DEFINE_RES_IRQ_NAMED(i2c->adapter_irq, "xe_i2c"); 118*f0e53aadSHeikki Krogerus 119*f0e53aadSHeikki Krogerus ret = platform_device_add_resources(pdev, &res, 1); 120*f0e53aadSHeikki Krogerus if (ret) 121*f0e53aadSHeikki Krogerus goto err_pdev_put; 122*f0e53aadSHeikki Krogerus } 123*f0e53aadSHeikki Krogerus 124*f0e53aadSHeikki Krogerus pdev->dev.parent = i2c->drm_dev; 125*f0e53aadSHeikki Krogerus pdev->dev.fwnode = fwnode; 126*f0e53aadSHeikki Krogerus i2c->adapter_node = fwnode; 127*f0e53aadSHeikki Krogerus i2c->pdev = pdev; 128*f0e53aadSHeikki Krogerus 129*f0e53aadSHeikki Krogerus ret = platform_device_add(pdev); 130*f0e53aadSHeikki Krogerus if (ret) 131*f0e53aadSHeikki Krogerus goto err_pdev_put; 132*f0e53aadSHeikki Krogerus 133*f0e53aadSHeikki Krogerus return 0; 134*f0e53aadSHeikki Krogerus 135*f0e53aadSHeikki Krogerus err_pdev_put: 136*f0e53aadSHeikki Krogerus platform_device_put(pdev); 137*f0e53aadSHeikki Krogerus err_fwnode_remove: 138*f0e53aadSHeikki Krogerus fwnode_remove_software_node(fwnode); 139*f0e53aadSHeikki Krogerus 140*f0e53aadSHeikki Krogerus return ret; 141*f0e53aadSHeikki Krogerus } 142*f0e53aadSHeikki Krogerus 143*f0e53aadSHeikki Krogerus static void xe_i2c_unregister_adapter(struct xe_i2c *i2c) 144*f0e53aadSHeikki Krogerus { 145*f0e53aadSHeikki Krogerus platform_device_unregister(i2c->pdev); 146*f0e53aadSHeikki Krogerus fwnode_remove_software_node(i2c->adapter_node); 147*f0e53aadSHeikki Krogerus } 148*f0e53aadSHeikki Krogerus 149*f0e53aadSHeikki Krogerus /** 150*f0e53aadSHeikki Krogerus * xe_i2c_irq_handler: Handler for I2C interrupts 151*f0e53aadSHeikki Krogerus * @xe: xe device instance 152*f0e53aadSHeikki Krogerus * @master_ctl: interrupt register 153*f0e53aadSHeikki Krogerus * 154*f0e53aadSHeikki Krogerus * Forward interrupts generated by the I2C host adapter to the I2C host adapter 155*f0e53aadSHeikki Krogerus * driver. 156*f0e53aadSHeikki Krogerus */ 157*f0e53aadSHeikki Krogerus void xe_i2c_irq_handler(struct xe_device *xe, u32 master_ctl) 158*f0e53aadSHeikki Krogerus { 159*f0e53aadSHeikki Krogerus if (!xe->i2c || !xe->i2c->adapter_irq) 160*f0e53aadSHeikki Krogerus return; 161*f0e53aadSHeikki Krogerus 162*f0e53aadSHeikki Krogerus if (master_ctl & I2C_IRQ) 163*f0e53aadSHeikki Krogerus generic_handle_irq_safe(xe->i2c->adapter_irq); 164*f0e53aadSHeikki Krogerus } 165*f0e53aadSHeikki Krogerus 166*f0e53aadSHeikki Krogerus static int xe_i2c_irq_map(struct irq_domain *h, unsigned int virq, 167*f0e53aadSHeikki Krogerus irq_hw_number_t hw_irq_num) 168*f0e53aadSHeikki Krogerus { 169*f0e53aadSHeikki Krogerus irq_set_chip_and_handler(virq, &dummy_irq_chip, handle_simple_irq); 170*f0e53aadSHeikki Krogerus return 0; 171*f0e53aadSHeikki Krogerus } 172*f0e53aadSHeikki Krogerus 173*f0e53aadSHeikki Krogerus static const struct irq_domain_ops xe_i2c_irq_ops = { 174*f0e53aadSHeikki Krogerus .map = xe_i2c_irq_map, 175*f0e53aadSHeikki Krogerus }; 176*f0e53aadSHeikki Krogerus 177*f0e53aadSHeikki Krogerus static int xe_i2c_create_irq(struct xe_i2c *i2c) 178*f0e53aadSHeikki Krogerus { 179*f0e53aadSHeikki Krogerus struct irq_domain *domain; 180*f0e53aadSHeikki Krogerus 181*f0e53aadSHeikki Krogerus if (!(i2c->ep.capabilities & XE_I2C_EP_CAP_IRQ)) 182*f0e53aadSHeikki Krogerus return 0; 183*f0e53aadSHeikki Krogerus 184*f0e53aadSHeikki Krogerus domain = irq_domain_create_linear(dev_fwnode(i2c->drm_dev), 1, &xe_i2c_irq_ops, NULL); 185*f0e53aadSHeikki Krogerus if (!domain) 186*f0e53aadSHeikki Krogerus return -ENOMEM; 187*f0e53aadSHeikki Krogerus 188*f0e53aadSHeikki Krogerus i2c->adapter_irq = irq_create_mapping(domain, 0); 189*f0e53aadSHeikki Krogerus i2c->irqdomain = domain; 190*f0e53aadSHeikki Krogerus 191*f0e53aadSHeikki Krogerus return 0; 192*f0e53aadSHeikki Krogerus } 193*f0e53aadSHeikki Krogerus 194*f0e53aadSHeikki Krogerus static void xe_i2c_remove_irq(struct xe_i2c *i2c) 195*f0e53aadSHeikki Krogerus { 196*f0e53aadSHeikki Krogerus if (!i2c->irqdomain) 197*f0e53aadSHeikki Krogerus return; 198*f0e53aadSHeikki Krogerus 199*f0e53aadSHeikki Krogerus irq_dispose_mapping(i2c->adapter_irq); 200*f0e53aadSHeikki Krogerus irq_domain_remove(i2c->irqdomain); 201*f0e53aadSHeikki Krogerus } 202*f0e53aadSHeikki Krogerus 203*f0e53aadSHeikki Krogerus static int xe_i2c_read(void *context, unsigned int reg, unsigned int *val) 204*f0e53aadSHeikki Krogerus { 205*f0e53aadSHeikki Krogerus struct xe_i2c *i2c = context; 206*f0e53aadSHeikki Krogerus 207*f0e53aadSHeikki Krogerus *val = xe_mmio_read32(i2c->mmio, XE_REG(reg + I2C_MEM_SPACE_OFFSET)); 208*f0e53aadSHeikki Krogerus 209*f0e53aadSHeikki Krogerus return 0; 210*f0e53aadSHeikki Krogerus } 211*f0e53aadSHeikki Krogerus 212*f0e53aadSHeikki Krogerus static int xe_i2c_write(void *context, unsigned int reg, unsigned int val) 213*f0e53aadSHeikki Krogerus { 214*f0e53aadSHeikki Krogerus struct xe_i2c *i2c = context; 215*f0e53aadSHeikki Krogerus 216*f0e53aadSHeikki Krogerus xe_mmio_write32(i2c->mmio, XE_REG(reg + I2C_MEM_SPACE_OFFSET), val); 217*f0e53aadSHeikki Krogerus 218*f0e53aadSHeikki Krogerus return 0; 219*f0e53aadSHeikki Krogerus } 220*f0e53aadSHeikki Krogerus 221*f0e53aadSHeikki Krogerus static const struct regmap_config i2c_regmap_config = { 222*f0e53aadSHeikki Krogerus .reg_bits = 32, 223*f0e53aadSHeikki Krogerus .val_bits = 32, 224*f0e53aadSHeikki Krogerus .reg_read = xe_i2c_read, 225*f0e53aadSHeikki Krogerus .reg_write = xe_i2c_write, 226*f0e53aadSHeikki Krogerus .fast_io = true, 227*f0e53aadSHeikki Krogerus }; 228*f0e53aadSHeikki Krogerus 229*f0e53aadSHeikki Krogerus static void xe_i2c_remove(void *data) 230*f0e53aadSHeikki Krogerus { 231*f0e53aadSHeikki Krogerus struct xe_i2c *i2c = data; 232*f0e53aadSHeikki Krogerus unsigned int i; 233*f0e53aadSHeikki Krogerus 234*f0e53aadSHeikki Krogerus for (i = 0; i < XE_I2C_MAX_CLIENTS; i++) 235*f0e53aadSHeikki Krogerus i2c_unregister_device(i2c->client[i]); 236*f0e53aadSHeikki Krogerus 237*f0e53aadSHeikki Krogerus bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier); 238*f0e53aadSHeikki Krogerus xe_i2c_unregister_adapter(i2c); 239*f0e53aadSHeikki Krogerus xe_i2c_remove_irq(i2c); 240*f0e53aadSHeikki Krogerus } 241*f0e53aadSHeikki Krogerus 242*f0e53aadSHeikki Krogerus /** 243*f0e53aadSHeikki Krogerus * xe_i2c_probe: Probe the I2C host adapter and the I2C clients attached to it 244*f0e53aadSHeikki Krogerus * @xe: xe device instance 245*f0e53aadSHeikki Krogerus * 246*f0e53aadSHeikki Krogerus * Register all the I2C devices described in the I2C Endpoint data structure. 247*f0e53aadSHeikki Krogerus * 248*f0e53aadSHeikki Krogerus * Return: 0 on success, error code on failure 249*f0e53aadSHeikki Krogerus */ 250*f0e53aadSHeikki Krogerus int xe_i2c_probe(struct xe_device *xe) 251*f0e53aadSHeikki Krogerus { 252*f0e53aadSHeikki Krogerus struct device *drm_dev = xe->drm.dev; 253*f0e53aadSHeikki Krogerus struct xe_i2c_endpoint ep; 254*f0e53aadSHeikki Krogerus struct regmap *regmap; 255*f0e53aadSHeikki Krogerus struct xe_i2c *i2c; 256*f0e53aadSHeikki Krogerus int ret; 257*f0e53aadSHeikki Krogerus 258*f0e53aadSHeikki Krogerus if (xe->info.platform != XE_BATTLEMAGE) 259*f0e53aadSHeikki Krogerus return 0; 260*f0e53aadSHeikki Krogerus 261*f0e53aadSHeikki Krogerus xe_i2c_read_endpoint(xe_root_tile_mmio(xe), &ep); 262*f0e53aadSHeikki Krogerus if (ep.cookie != XE_I2C_EP_COOKIE_DEVICE) 263*f0e53aadSHeikki Krogerus return 0; 264*f0e53aadSHeikki Krogerus 265*f0e53aadSHeikki Krogerus i2c = devm_kzalloc(drm_dev, sizeof(*i2c), GFP_KERNEL); 266*f0e53aadSHeikki Krogerus if (!i2c) 267*f0e53aadSHeikki Krogerus return -ENOMEM; 268*f0e53aadSHeikki Krogerus 269*f0e53aadSHeikki Krogerus INIT_WORK(&i2c->work, xe_i2c_client_work); 270*f0e53aadSHeikki Krogerus i2c->mmio = xe_root_tile_mmio(xe); 271*f0e53aadSHeikki Krogerus i2c->drm_dev = drm_dev; 272*f0e53aadSHeikki Krogerus i2c->ep = ep; 273*f0e53aadSHeikki Krogerus 274*f0e53aadSHeikki Krogerus regmap = devm_regmap_init(drm_dev, NULL, i2c, &i2c_regmap_config); 275*f0e53aadSHeikki Krogerus if (IS_ERR(regmap)) 276*f0e53aadSHeikki Krogerus return PTR_ERR(regmap); 277*f0e53aadSHeikki Krogerus 278*f0e53aadSHeikki Krogerus i2c->bus_notifier.notifier_call = xe_i2c_notifier; 279*f0e53aadSHeikki Krogerus ret = bus_register_notifier(&i2c_bus_type, &i2c->bus_notifier); 280*f0e53aadSHeikki Krogerus if (ret) 281*f0e53aadSHeikki Krogerus return ret; 282*f0e53aadSHeikki Krogerus 283*f0e53aadSHeikki Krogerus ret = xe_i2c_create_irq(i2c); 284*f0e53aadSHeikki Krogerus if (ret) 285*f0e53aadSHeikki Krogerus goto err_unregister_notifier; 286*f0e53aadSHeikki Krogerus 287*f0e53aadSHeikki Krogerus ret = xe_i2c_register_adapter(i2c); 288*f0e53aadSHeikki Krogerus if (ret) 289*f0e53aadSHeikki Krogerus goto err_remove_irq; 290*f0e53aadSHeikki Krogerus 291*f0e53aadSHeikki Krogerus return devm_add_action_or_reset(drm_dev, xe_i2c_remove, i2c); 292*f0e53aadSHeikki Krogerus 293*f0e53aadSHeikki Krogerus err_remove_irq: 294*f0e53aadSHeikki Krogerus xe_i2c_remove_irq(i2c); 295*f0e53aadSHeikki Krogerus 296*f0e53aadSHeikki Krogerus err_unregister_notifier: 297*f0e53aadSHeikki Krogerus bus_unregister_notifier(&i2c_bus_type, &i2c->bus_notifier); 298*f0e53aadSHeikki Krogerus 299*f0e53aadSHeikki Krogerus return ret; 300*f0e53aadSHeikki Krogerus } 301