// SPDX-License-Identifier: GPL-2.0+ /* * Texas Instruments' K3 Error Signalling Module driver * * Copyright (C) 2019 Texas Instruments Incorporated - http://www.ti.com/ * Tero Kristo * */ #include #include #include #include #include #include #define ESM_SFT_RST 0x0c #define ESM_SFT_RST_KEY 0x0f #define ESM_EN 0x08 #define ESM_EN_KEY 0x0f #define ESM_STS(i) (0x404 + (i) / 32 * 0x20) #define ESM_STS_MASK(i) (1 << ((i) % 32)) #define ESM_PIN_EN_SET_OFFSET(i) (0x414 + (i) / 32 * 0x20) #define ESM_PIN_MASK(i) (1 << ((i) % 32)) #define ESM_INTR_EN_SET_OFFSET(i) (0x408 + (i) / 32 * 0x20) #define ESM_INTR_MASK(i) (1 << ((i) % 32)) #define ESM_INTR_PRIO_SET_OFFSET(i) (0x410 + (i) / 32 * 0x20) #define ESM_INTR_PRIO_MASK(i) (1 << ((i) % 32)) static void esm_pin_enable(void __iomem *base, int pin) { u32 value; value = readl(base + ESM_PIN_EN_SET_OFFSET(pin)); value |= ESM_PIN_MASK(pin); /* Enable event */ writel(value, base + ESM_PIN_EN_SET_OFFSET(pin)); } static void esm_intr_enable(void __iomem *base, int pin) { u32 value; value = readl(base + ESM_INTR_EN_SET_OFFSET(pin)); value |= ESM_INTR_MASK(pin); /* Enable Interrupt event */ writel(value, base + ESM_INTR_EN_SET_OFFSET(pin)); } static void esm_intr_prio_set(void __iomem *base, int pin) { u32 value; value = readl(base + ESM_INTR_PRIO_SET_OFFSET(pin)); value |= ESM_INTR_PRIO_MASK(pin); /* Set to priority */ writel(value, base + ESM_INTR_PRIO_SET_OFFSET(pin)); } static void esm_clear_raw_status(void __iomem *base, int pin) { u32 value; value = readl(base + ESM_STS(pin)); value |= ESM_STS_MASK(pin); /* Clear Event status */ writel(value, base + ESM_STS(pin)); } /** * k3_esm_probe: configures ESM based on DT data * * Parses ESM info from device tree, and configures the module accordingly. */ static int k3_esm_probe(struct udevice *dev) { int ret; void __iomem *base; int num_pins; u32 *pins; int i; base = dev_remap_addr_index(dev, 0); if (!base) return -ENODEV; num_pins = dev_read_size(dev, "ti,esm-pins"); if (num_pins < 0) { dev_err(dev, "ti,esm-pins property missing or invalid: %d\n", num_pins); return num_pins; } num_pins /= sizeof(u32); pins = kmalloc(num_pins * sizeof(u32), __GFP_ZERO); if (!pins) return -ENOMEM; ret = dev_read_u32_array(dev, "ti,esm-pins", pins, num_pins); if (ret < 0) { dev_err(dev, "failed to read ti,esm-pins property: %d\n", ret); goto free_pins; } /* Clear any pending events */ writel(ESM_SFT_RST_KEY, base + ESM_SFT_RST); for (i = 0; i < num_pins; i++) { esm_intr_prio_set(base, pins[i]); esm_clear_raw_status(base, pins[i]); esm_pin_enable(base, pins[i]); esm_intr_enable(base, pins[i]); } /* Enable ESM */ writel(ESM_EN_KEY, base + ESM_EN); free_pins: kfree(pins); return ret; } static const struct udevice_id k3_esm_ids[] = { { .compatible = "ti,j721e-esm" }, {} }; U_BOOT_DRIVER(k3_esm) = { .name = "k3_esm", .of_match = k3_esm_ids, .id = UCLASS_MISC, .probe = k3_esm_probe, };