Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Merge branches 'ib-mfd-acpi-for-rafael-5.20', 'ib-mfd-edac-i2c-leds-pinctrl-platform-watchdog-5.20' and 'ib-mfd-soc-bcm-5.20' into ibs-for-mfd-merged

+567 -287
+1
drivers/edac/Kconfig
··· 263 263 config EDAC_PND2 264 264 tristate "Intel Pondicherry2" 265 265 depends on PCI && X86_64 && X86_MCE_INTEL 266 + select P2SB if X86 266 267 help 267 268 Support for error detection and correction on the Intel 268 269 Pondicherry2 Integrated Memory Controller. This SoC IP is
+20 -42
drivers/edac/pnd2_edac.c
··· 28 28 #include <linux/bitmap.h> 29 29 #include <linux/math64.h> 30 30 #include <linux/mod_devicetable.h> 31 + #include <linux/platform_data/x86/p2sb.h> 32 + 31 33 #include <asm/cpu_device_id.h> 32 34 #include <asm/intel-family.h> 33 35 #include <asm/processor.h> ··· 234 232 return U64_LSHIFT(hi.base, 32) | U64_LSHIFT(lo.base, 15); 235 233 } 236 234 237 - static u64 get_sideband_reg_base_addr(void) 238 - { 239 - struct pci_dev *pdev; 240 - u32 hi, lo; 241 - u8 hidden; 242 - 243 - pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x19dd, NULL); 244 - if (pdev) { 245 - /* Unhide the P2SB device, if it's hidden */ 246 - pci_read_config_byte(pdev, 0xe1, &hidden); 247 - if (hidden) 248 - pci_write_config_byte(pdev, 0xe1, 0); 249 - 250 - pci_read_config_dword(pdev, 0x10, &lo); 251 - pci_read_config_dword(pdev, 0x14, &hi); 252 - lo &= 0xfffffff0; 253 - 254 - /* Hide the P2SB device, if it was hidden before */ 255 - if (hidden) 256 - pci_write_config_byte(pdev, 0xe1, hidden); 257 - 258 - pci_dev_put(pdev); 259 - return (U64_LSHIFT(hi, 32) | U64_LSHIFT(lo, 0)); 260 - } else { 261 - return 0xfd000000; 262 - } 263 - } 264 - 265 235 #define DNV_MCHBAR_SIZE 0x8000 266 236 #define DNV_SB_PORT_SIZE 0x10000 267 237 static int dnv_rd_reg(int port, int off, int op, void *data, size_t sz, char *name) 268 238 { 269 239 struct pci_dev *pdev; 270 - char *base; 271 - u64 addr; 272 - unsigned long size; 240 + void __iomem *base; 241 + struct resource r; 242 + int ret; 273 243 274 244 if (op == 4) { 275 245 pdev = pci_get_device(PCI_VENDOR_ID_INTEL, 0x1980, NULL); ··· 253 279 } else { 254 280 /* MMIO via memory controller hub base address */ 255 281 if (op == 0 && port == 0x4c) { 256 - addr = get_mem_ctrl_hub_base_addr(); 257 - if (!addr) 282 + memset(&r, 0, sizeof(r)); 283 + 284 + r.start = get_mem_ctrl_hub_base_addr(); 285 + if (!r.start) 258 286 return -ENODEV; 259 - size = DNV_MCHBAR_SIZE; 287 + r.end = r.start + DNV_MCHBAR_SIZE - 1; 260 288 } else { 261 289 /* MMIO via sideband register base address */ 262 - addr = get_sideband_reg_base_addr(); 263 - if (!addr) 264 - return -ENODEV; 265 - addr += (port << 16); 266 - size = DNV_SB_PORT_SIZE; 290 + ret = p2sb_bar(NULL, 0, &r); 291 + if (ret) 292 + return ret; 293 + 294 + r.start += (port << 16); 295 + r.end = r.start + DNV_SB_PORT_SIZE - 1; 267 296 } 268 297 269 - base = ioremap((resource_size_t)addr, size); 298 + base = ioremap(r.start, resource_size(&r)); 270 299 if (!base) 271 300 return -ENODEV; 272 301 273 302 if (sz == 8) 274 - *(u32 *)(data + 4) = *(u32 *)(base + off + 4); 275 - *(u32 *)data = *(u32 *)(base + off); 303 + *(u64 *)data = readq(base + off); 304 + else 305 + *(u32 *)data = readl(base + off); 276 306 277 307 iounmap(base); 278 308 }
+1
drivers/i2c/busses/Kconfig
··· 108 108 config I2C_I801 109 109 tristate "Intel 82801 (ICH/PCH)" 110 110 depends on PCI 111 + select P2SB if X86 111 112 select CHECK_SIGNATURE if X86 && DMI 112 113 select I2C_SMBUS 113 114 help
+9 -30
drivers/i2c/busses/i2c-i801.c
··· 111 111 #include <linux/err.h> 112 112 #include <linux/platform_device.h> 113 113 #include <linux/platform_data/itco_wdt.h> 114 + #include <linux/platform_data/x86/p2sb.h> 114 115 #include <linux/pm_runtime.h> 115 116 #include <linux/mutex.h> 116 117 ··· 141 140 #define TCOBASE 0x050 142 141 #define TCOCTL 0x054 143 142 144 - #define SBREG_BAR 0x10 145 143 #define SBREG_SMBCTRL 0xc6000c 146 144 #define SBREG_SMBCTRL_DNV 0xcf000c 147 145 ··· 1482 1482 .version = 4, 1483 1483 }; 1484 1484 struct resource *res; 1485 - unsigned int devfn; 1486 - u64 base64_addr; 1487 - u32 base_addr; 1488 - u8 hidden; 1485 + int ret; 1489 1486 1490 1487 /* 1491 1488 * We must access the NO_REBOOT bit over the Primary to Sideband 1492 - * bridge (P2SB). The BIOS prevents the P2SB device from being 1493 - * enumerated by the PCI subsystem, so we need to unhide/hide it 1494 - * to lookup the P2SB BAR. 1489 + * (P2SB) bridge. 1495 1490 */ 1496 - pci_lock_rescan_remove(); 1497 - 1498 - devfn = PCI_DEVFN(PCI_SLOT(pci_dev->devfn), 1); 1499 - 1500 - /* Unhide the P2SB device, if it is hidden */ 1501 - pci_bus_read_config_byte(pci_dev->bus, devfn, 0xe1, &hidden); 1502 - if (hidden) 1503 - pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, 0x0); 1504 - 1505 - pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR, &base_addr); 1506 - base64_addr = base_addr & 0xfffffff0; 1507 - 1508 - pci_bus_read_config_dword(pci_dev->bus, devfn, SBREG_BAR + 0x4, &base_addr); 1509 - base64_addr |= (u64)base_addr << 32; 1510 - 1511 - /* Hide the P2SB device, if it was hidden before */ 1512 - if (hidden) 1513 - pci_bus_write_config_byte(pci_dev->bus, devfn, 0xe1, hidden); 1514 - pci_unlock_rescan_remove(); 1515 1491 1516 1492 res = &tco_res[1]; 1493 + ret = p2sb_bar(pci_dev->bus, 0, res); 1494 + if (ret) 1495 + return ERR_PTR(ret); 1496 + 1517 1497 if (pci_dev->device == PCI_DEVICE_ID_INTEL_DNV_SMBUS) 1518 - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL_DNV; 1498 + res->start += SBREG_SMBCTRL_DNV; 1519 1499 else 1520 - res->start = (resource_size_t)base64_addr + SBREG_SMBCTRL; 1500 + res->start += SBREG_SMBCTRL; 1521 1501 1522 1502 res->end = res->start + 3; 1523 - res->flags = IORESOURCE_MEM; 1524 1503 1525 1504 return platform_device_register_resndata(&pci_dev->dev, "iTCO_wdt", -1, 1526 1505 tco_res, 2, &pldata, sizeof(pldata));
+3 -3
drivers/leds/simple/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0-only 2 2 config LEDS_SIEMENS_SIMATIC_IPC 3 3 tristate "LED driver for Siemens Simatic IPCs" 4 - depends on LEDS_CLASS 4 + depends on LEDS_GPIO 5 5 depends on SIEMENS_SIMATIC_IPC 6 6 help 7 7 This option enables support for the LEDs of several Industrial PCs 8 8 from Siemens. 9 9 10 - To compile this driver as a module, choose M here: the module 11 - will be called simatic-ipc-leds. 10 + To compile this driver as a module, choose M here: the modules 11 + will be called simatic-ipc-leds and simatic-ipc-leds-gpio.
+1
drivers/leds/simple/Makefile
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds.o 3 + obj-$(CONFIG_LEDS_SIEMENS_SIMATIC_IPC) += simatic-ipc-leds-gpio.o
+105
drivers/leds/simple/simatic-ipc-leds-gpio.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Siemens SIMATIC IPC driver for GPIO based LEDs 4 + * 5 + * Copyright (c) Siemens AG, 2022 6 + * 7 + * Authors: 8 + * Henning Schild <henning.schild@siemens.com> 9 + */ 10 + 11 + #include <linux/gpio/machine.h> 12 + #include <linux/gpio/consumer.h> 13 + #include <linux/leds.h> 14 + #include <linux/module.h> 15 + #include <linux/platform_device.h> 16 + 17 + static struct gpiod_lookup_table simatic_ipc_led_gpio_table = { 18 + .dev_id = "leds-gpio", 19 + .table = { 20 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 51, NULL, 0, GPIO_ACTIVE_LOW), 21 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 52, NULL, 1, GPIO_ACTIVE_LOW), 22 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 53, NULL, 2, GPIO_ACTIVE_LOW), 23 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 57, NULL, 3, GPIO_ACTIVE_LOW), 24 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 58, NULL, 4, GPIO_ACTIVE_LOW), 25 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 60, NULL, 5, GPIO_ACTIVE_LOW), 26 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 56, NULL, 6, GPIO_ACTIVE_LOW), 27 + GPIO_LOOKUP_IDX("apollolake-pinctrl.0", 59, NULL, 7, GPIO_ACTIVE_HIGH), 28 + }, 29 + }; 30 + 31 + static const struct gpio_led simatic_ipc_gpio_leds[] = { 32 + { .name = "green:" LED_FUNCTION_STATUS "-3" }, 33 + { .name = "red:" LED_FUNCTION_STATUS "-1" }, 34 + { .name = "green:" LED_FUNCTION_STATUS "-1" }, 35 + { .name = "red:" LED_FUNCTION_STATUS "-2" }, 36 + { .name = "green:" LED_FUNCTION_STATUS "-2" }, 37 + { .name = "red:" LED_FUNCTION_STATUS "-3" }, 38 + }; 39 + 40 + static const struct gpio_led_platform_data simatic_ipc_gpio_leds_pdata = { 41 + .num_leds = ARRAY_SIZE(simatic_ipc_gpio_leds), 42 + .leds = simatic_ipc_gpio_leds, 43 + }; 44 + 45 + static struct platform_device *simatic_leds_pdev; 46 + 47 + static int simatic_ipc_leds_gpio_remove(struct platform_device *pdev) 48 + { 49 + gpiod_remove_lookup_table(&simatic_ipc_led_gpio_table); 50 + platform_device_unregister(simatic_leds_pdev); 51 + 52 + return 0; 53 + } 54 + 55 + static int simatic_ipc_leds_gpio_probe(struct platform_device *pdev) 56 + { 57 + struct gpio_desc *gpiod; 58 + int err; 59 + 60 + gpiod_add_lookup_table(&simatic_ipc_led_gpio_table); 61 + simatic_leds_pdev = platform_device_register_resndata(NULL, 62 + "leds-gpio", PLATFORM_DEVID_NONE, NULL, 0, 63 + &simatic_ipc_gpio_leds_pdata, 64 + sizeof(simatic_ipc_gpio_leds_pdata)); 65 + if (IS_ERR(simatic_leds_pdev)) { 66 + err = PTR_ERR(simatic_leds_pdev); 67 + goto out; 68 + } 69 + 70 + /* PM_BIOS_BOOT_N */ 71 + gpiod = gpiod_get_index(&simatic_leds_pdev->dev, NULL, 6, GPIOD_OUT_LOW); 72 + if (IS_ERR(gpiod)) { 73 + err = PTR_ERR(gpiod); 74 + goto out; 75 + } 76 + gpiod_put(gpiod); 77 + 78 + /* PM_WDT_OUT */ 79 + gpiod = gpiod_get_index(&simatic_leds_pdev->dev, NULL, 7, GPIOD_OUT_LOW); 80 + if (IS_ERR(gpiod)) { 81 + err = PTR_ERR(gpiod); 82 + goto out; 83 + } 84 + gpiod_put(gpiod); 85 + 86 + return 0; 87 + out: 88 + simatic_ipc_leds_gpio_remove(pdev); 89 + 90 + return err; 91 + } 92 + 93 + static struct platform_driver simatic_ipc_led_gpio_driver = { 94 + .probe = simatic_ipc_leds_gpio_probe, 95 + .remove = simatic_ipc_leds_gpio_remove, 96 + .driver = { 97 + .name = KBUILD_MODNAME, 98 + } 99 + }; 100 + module_platform_driver(simatic_ipc_led_gpio_driver); 101 + 102 + MODULE_LICENSE("GPL v2"); 103 + MODULE_ALIAS("platform:" KBUILD_MODNAME); 104 + MODULE_SOFTDEP("pre: platform:leds-gpio"); 105 + MODULE_AUTHOR("Henning Schild <henning.schild@siemens.com>");
+4 -76
drivers/leds/simple/simatic-ipc-leds.c
··· 23 23 #define SIMATIC_IPC_LED_PORT_BASE 0x404E 24 24 25 25 struct simatic_ipc_led { 26 - unsigned int value; /* mask for io and offset for mem */ 26 + unsigned int value; /* mask for io */ 27 27 char *name; 28 28 struct led_classdev cdev; 29 29 }; ··· 35 35 {1 << 6, "yellow:" LED_FUNCTION_STATUS "-2" }, 36 36 {1 << 13, "red:" LED_FUNCTION_STATUS "-3" }, 37 37 {1 << 5, "yellow:" LED_FUNCTION_STATUS "-3" }, 38 - { } 39 - }; 40 - 41 - /* the actual start will be discovered with PCI, 0 is a placeholder */ 42 - static struct resource simatic_ipc_led_mem_res = DEFINE_RES_MEM_NAMED(0, SZ_4K, KBUILD_MODNAME); 43 - 44 - static void __iomem *simatic_ipc_led_memory; 45 - 46 - static struct simatic_ipc_led simatic_ipc_leds_mem[] = { 47 - {0x500 + 0x1A0, "red:" LED_FUNCTION_STATUS "-1"}, 48 - {0x500 + 0x1A8, "green:" LED_FUNCTION_STATUS "-1"}, 49 - {0x500 + 0x1C8, "red:" LED_FUNCTION_STATUS "-2"}, 50 - {0x500 + 0x1D0, "green:" LED_FUNCTION_STATUS "-2"}, 51 - {0x500 + 0x1E0, "red:" LED_FUNCTION_STATUS "-3"}, 52 - {0x500 + 0x198, "green:" LED_FUNCTION_STATUS "-3"}, 53 38 { } 54 39 }; 55 40 ··· 73 88 return inw(SIMATIC_IPC_LED_PORT_BASE) & led->value ? LED_OFF : led_cd->max_brightness; 74 89 } 75 90 76 - static void simatic_ipc_led_set_mem(struct led_classdev *led_cd, 77 - enum led_brightness brightness) 78 - { 79 - struct simatic_ipc_led *led = cdev_to_led(led_cd); 80 - void __iomem *reg = simatic_ipc_led_memory + led->value; 81 - u32 val; 82 - 83 - val = readl(reg); 84 - val = (val & ~1) | (brightness == LED_OFF); 85 - writel(val, reg); 86 - } 87 - 88 - static enum led_brightness simatic_ipc_led_get_mem(struct led_classdev *led_cd) 89 - { 90 - struct simatic_ipc_led *led = cdev_to_led(led_cd); 91 - void __iomem *reg = simatic_ipc_led_memory + led->value; 92 - u32 val; 93 - 94 - val = readl(reg); 95 - return (val & 1) ? LED_OFF : led_cd->max_brightness; 96 - } 97 - 98 91 static int simatic_ipc_leds_probe(struct platform_device *pdev) 99 92 { 100 93 const struct simatic_ipc_platform *plat = pdev->dev.platform_data; ··· 80 117 struct simatic_ipc_led *ipcled; 81 118 struct led_classdev *cdev; 82 119 struct resource *res; 83 - void __iomem *reg; 84 - int err, type; 85 - u32 val; 120 + int err; 86 121 87 122 switch (plat->devmode) { 88 123 case SIMATIC_IPC_DEVICE_227D: ··· 95 134 } 96 135 ipcled = simatic_ipc_leds_io; 97 136 } 98 - type = IORESOURCE_IO; 99 137 if (!devm_request_region(dev, res->start, resource_size(res), KBUILD_MODNAME)) { 100 138 dev_err(dev, "Unable to register IO resource at %pR\n", res); 101 139 return -EBUSY; 102 140 } 103 - break; 104 - case SIMATIC_IPC_DEVICE_127E: 105 - res = &simatic_ipc_led_mem_res; 106 - ipcled = simatic_ipc_leds_mem; 107 - type = IORESOURCE_MEM; 108 - 109 - /* get GPIO base from PCI */ 110 - res->start = simatic_ipc_get_membase0(PCI_DEVFN(13, 0)); 111 - if (res->start == 0) 112 - return -ENODEV; 113 - 114 - /* do the final address calculation */ 115 - res->start = res->start + (0xC5 << 16); 116 - res->end += res->start; 117 - 118 - simatic_ipc_led_memory = devm_ioremap_resource(dev, res); 119 - if (IS_ERR(simatic_ipc_led_memory)) 120 - return PTR_ERR(simatic_ipc_led_memory); 121 - 122 - /* initialize power/watchdog LED */ 123 - reg = simatic_ipc_led_memory + 0x500 + 0x1D8; /* PM_WDT_OUT */ 124 - val = readl(reg); 125 - writel(val & ~1, reg); 126 - 127 - reg = simatic_ipc_led_memory + 0x500 + 0x1C0; /* PM_BIOS_BOOT_N */ 128 - val = readl(reg); 129 - writel(val | 1, reg); 130 141 break; 131 142 default: 132 143 return -ENODEV; ··· 106 173 107 174 while (ipcled->value) { 108 175 cdev = &ipcled->cdev; 109 - if (type == IORESOURCE_MEM) { 110 - cdev->brightness_set = simatic_ipc_led_set_mem; 111 - cdev->brightness_get = simatic_ipc_led_get_mem; 112 - } else { 113 - cdev->brightness_set = simatic_ipc_led_set_io; 114 - cdev->brightness_get = simatic_ipc_led_get_io; 115 - } 176 + cdev->brightness_set = simatic_ipc_led_set_io; 177 + cdev->brightness_get = simatic_ipc_led_get_io; 116 178 cdev->max_brightness = LED_ON; 117 179 cdev->name = ipcled->name; 118 180
+1
drivers/mfd/Kconfig
··· 572 572 tristate "Intel ICH LPC" 573 573 depends on PCI 574 574 select MFD_CORE 575 + select P2SB if X86 575 576 help 576 577 The LPC bridge function of the Intel ICH provides support for 577 578 many functional units. This driver provides needed support for
+54 -20
drivers/mfd/bcm2835-pm.c
··· 25 25 { .name = "bcm2835-power" }, 26 26 }; 27 27 28 + static int bcm2835_pm_get_pdata(struct platform_device *pdev, 29 + struct bcm2835_pm *pm) 30 + { 31 + if (of_find_property(pm->dev->of_node, "reg-names", NULL)) { 32 + struct resource *res; 33 + 34 + pm->base = devm_platform_ioremap_resource_byname(pdev, "pm"); 35 + if (IS_ERR(pm->base)) 36 + return PTR_ERR(pm->base); 37 + 38 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "asb"); 39 + if (res) { 40 + pm->asb = devm_ioremap_resource(&pdev->dev, res); 41 + if (IS_ERR(pm->asb)) 42 + pm->asb = NULL; 43 + } 44 + 45 + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, 46 + "rpivid_asb"); 47 + if (res) { 48 + pm->rpivid_asb = devm_ioremap_resource(&pdev->dev, res); 49 + if (IS_ERR(pm->rpivid_asb)) 50 + pm->rpivid_asb = NULL; 51 + } 52 + 53 + return 0; 54 + } 55 + 56 + /* If no 'reg-names' property is found we can assume we're using old DTB. */ 57 + pm->base = devm_platform_ioremap_resource(pdev, 0); 58 + if (IS_ERR(pm->base)) 59 + return PTR_ERR(pm->base); 60 + 61 + pm->asb = devm_platform_ioremap_resource(pdev, 1); 62 + if (IS_ERR(pm->asb)) 63 + pm->asb = NULL; 64 + 65 + pm->rpivid_asb = devm_platform_ioremap_resource(pdev, 2); 66 + if (IS_ERR(pm->rpivid_asb)) 67 + pm->rpivid_asb = NULL; 68 + 69 + return 0; 70 + } 71 + 28 72 static int bcm2835_pm_probe(struct platform_device *pdev) 29 73 { 30 - struct resource *res; 31 74 struct device *dev = &pdev->dev; 32 75 struct bcm2835_pm *pm; 33 76 int ret; ··· 82 39 83 40 pm->dev = dev; 84 41 85 - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); 86 - pm->base = devm_ioremap_resource(dev, res); 87 - if (IS_ERR(pm->base)) 88 - return PTR_ERR(pm->base); 42 + ret = bcm2835_pm_get_pdata(pdev, pm); 43 + if (ret) 44 + return ret; 89 45 90 46 ret = devm_mfd_add_devices(dev, -1, 91 47 bcm2835_pm_devs, ARRAY_SIZE(bcm2835_pm_devs), ··· 92 50 if (ret) 93 51 return ret; 94 52 95 - /* We'll use the presence of the AXI ASB regs in the 53 + /* 54 + * We'll use the presence of the AXI ASB regs in the 96 55 * bcm2835-pm binding as the key for whether we can reference 97 56 * the full PM register range and support power domains. 98 57 */ 99 - res = platform_get_resource(pdev, IORESOURCE_MEM, 1); 100 - if (res) { 101 - pm->asb = devm_ioremap_resource(dev, res); 102 - if (IS_ERR(pm->asb)) 103 - return PTR_ERR(pm->asb); 104 - 105 - ret = devm_mfd_add_devices(dev, -1, 106 - bcm2835_power_devs, 107 - ARRAY_SIZE(bcm2835_power_devs), 108 - NULL, 0, NULL); 109 - if (ret) 110 - return ret; 111 - } 112 - 58 + if (pm->asb) 59 + return devm_mfd_add_devices(dev, -1, bcm2835_power_devs, 60 + ARRAY_SIZE(bcm2835_power_devs), 61 + NULL, 0, NULL); 113 62 return 0; 114 63 } 115 64 116 65 static const struct of_device_id bcm2835_pm_of_match[] = { 117 66 { .compatible = "brcm,bcm2835-pm-wdt", }, 118 67 { .compatible = "brcm,bcm2835-pm", }, 68 + { .compatible = "brcm,bcm2711-pm", }, 119 69 {}, 120 70 }; 121 71 MODULE_DEVICE_TABLE(of, bcm2835_pm_of_match);
+125 -36
drivers/mfd/lpc_ich.c
··· 8 8 * Configuration Registers. 9 9 * 10 10 * This driver is derived from lpc_sch. 11 - 11 + * 12 + * Copyright (c) 2017, 2021-2022 Intel Corporation 12 13 * Copyright (c) 2011 Extreme Engineering Solution, Inc. 13 14 * Author: Aaron Sierra <asierra@xes-inc.com> 14 15 * ··· 43 42 #include <linux/errno.h> 44 43 #include <linux/acpi.h> 45 44 #include <linux/pci.h> 45 + #include <linux/pinctrl/pinctrl.h> 46 46 #include <linux/mfd/core.h> 47 47 #include <linux/mfd/lpc_ich.h> 48 48 #include <linux/platform_data/itco_wdt.h> 49 + #include <linux/platform_data/x86/p2sb.h> 49 50 50 51 #define ACPIBASE 0x40 51 52 #define ACPIBASE_GPE_OFF 0x28 ··· 73 70 #define SPIBASE_LPT_SZ 512 74 71 #define BCR 0xdc 75 72 #define BCR_WPD BIT(0) 76 - 77 - #define SPIBASE_APL_SZ 4096 78 73 79 74 #define GPIOBASE_ICH0 0x58 80 75 #define GPIOCTRL_ICH0 0x5C ··· 144 143 .ignore_resource_conflicts = true, 145 144 }; 146 145 146 + #define APL_GPIO_NORTH 0 147 + #define APL_GPIO_NORTHWEST 1 148 + #define APL_GPIO_WEST 2 149 + #define APL_GPIO_SOUTHWEST 3 150 + #define APL_GPIO_NR_DEVICES 4 151 + 152 + /* Offset data for Apollo Lake GPIO controllers */ 153 + static resource_size_t apl_gpio_offsets[APL_GPIO_NR_DEVICES] = { 154 + [APL_GPIO_NORTH] = 0xc50000, 155 + [APL_GPIO_NORTHWEST] = 0xc40000, 156 + [APL_GPIO_WEST] = 0xc70000, 157 + [APL_GPIO_SOUTHWEST] = 0xc00000, 158 + }; 159 + 160 + #define APL_GPIO_RESOURCE_SIZE 0x1000 161 + 162 + #define APL_GPIO_IRQ 14 163 + 164 + static struct resource apl_gpio_resources[APL_GPIO_NR_DEVICES][2] = { 165 + [APL_GPIO_NORTH] = { 166 + DEFINE_RES_MEM(0, 0), 167 + DEFINE_RES_IRQ(APL_GPIO_IRQ), 168 + }, 169 + [APL_GPIO_NORTHWEST] = { 170 + DEFINE_RES_MEM(0, 0), 171 + DEFINE_RES_IRQ(APL_GPIO_IRQ), 172 + }, 173 + [APL_GPIO_WEST] = { 174 + DEFINE_RES_MEM(0, 0), 175 + DEFINE_RES_IRQ(APL_GPIO_IRQ), 176 + }, 177 + [APL_GPIO_SOUTHWEST] = { 178 + DEFINE_RES_MEM(0, 0), 179 + DEFINE_RES_IRQ(APL_GPIO_IRQ), 180 + }, 181 + }; 182 + 183 + static const struct mfd_cell apl_gpio_devices[APL_GPIO_NR_DEVICES] = { 184 + [APL_GPIO_NORTH] = { 185 + .name = "apollolake-pinctrl", 186 + .id = APL_GPIO_NORTH, 187 + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTH]), 188 + .resources = apl_gpio_resources[APL_GPIO_NORTH], 189 + .ignore_resource_conflicts = true, 190 + }, 191 + [APL_GPIO_NORTHWEST] = { 192 + .name = "apollolake-pinctrl", 193 + .id = APL_GPIO_NORTHWEST, 194 + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_NORTHWEST]), 195 + .resources = apl_gpio_resources[APL_GPIO_NORTHWEST], 196 + .ignore_resource_conflicts = true, 197 + }, 198 + [APL_GPIO_WEST] = { 199 + .name = "apollolake-pinctrl", 200 + .id = APL_GPIO_WEST, 201 + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_WEST]), 202 + .resources = apl_gpio_resources[APL_GPIO_WEST], 203 + .ignore_resource_conflicts = true, 204 + }, 205 + [APL_GPIO_SOUTHWEST] = { 206 + .name = "apollolake-pinctrl", 207 + .id = APL_GPIO_SOUTHWEST, 208 + .num_resources = ARRAY_SIZE(apl_gpio_resources[APL_GPIO_SOUTHWEST]), 209 + .resources = apl_gpio_resources[APL_GPIO_SOUTHWEST], 210 + .ignore_resource_conflicts = true, 211 + }, 212 + }; 147 213 148 214 static struct mfd_cell lpc_ich_spi_cell = { 149 215 .name = "intel-spi", ··· 1154 1086 return ret; 1155 1087 } 1156 1088 1089 + static int lpc_ich_init_pinctrl(struct pci_dev *dev) 1090 + { 1091 + struct resource base; 1092 + unsigned int i; 1093 + int ret; 1094 + 1095 + /* Check, if GPIO has been exported as an ACPI device */ 1096 + if (acpi_dev_present("INT3452", NULL, -1)) 1097 + return -EEXIST; 1098 + 1099 + ret = p2sb_bar(dev->bus, 0, &base); 1100 + if (ret) 1101 + return ret; 1102 + 1103 + for (i = 0; i < ARRAY_SIZE(apl_gpio_devices); i++) { 1104 + struct resource *mem = &apl_gpio_resources[i][0]; 1105 + resource_size_t offset = apl_gpio_offsets[i]; 1106 + 1107 + /* Fill MEM resource */ 1108 + mem->start = base.start + offset; 1109 + mem->end = base.start + offset + APL_GPIO_RESOURCE_SIZE - 1; 1110 + mem->flags = base.flags; 1111 + } 1112 + 1113 + return mfd_add_devices(&dev->dev, 0, apl_gpio_devices, 1114 + ARRAY_SIZE(apl_gpio_devices), NULL, 0, NULL); 1115 + } 1116 + 1157 1117 static bool lpc_ich_byt_set_writeable(void __iomem *base, void *data) 1158 1118 { 1159 1119 u32 val; ··· 1196 1100 return val & BYT_BCR_WPD; 1197 1101 } 1198 1102 1199 - static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data) 1103 + static bool lpc_ich_set_writeable(struct pci_bus *bus, unsigned int devfn) 1200 1104 { 1201 - struct pci_dev *pdev = data; 1202 1105 u32 bcr; 1203 1106 1204 - pci_read_config_dword(pdev, BCR, &bcr); 1107 + pci_bus_read_config_dword(bus, devfn, BCR, &bcr); 1205 1108 if (!(bcr & BCR_WPD)) { 1206 1109 bcr |= BCR_WPD; 1207 - pci_write_config_dword(pdev, BCR, bcr); 1208 - pci_read_config_dword(pdev, BCR, &bcr); 1110 + pci_bus_write_config_dword(bus, devfn, BCR, bcr); 1111 + pci_bus_read_config_dword(bus, devfn, BCR, &bcr); 1209 1112 } 1210 1113 1211 1114 return bcr & BCR_WPD; 1212 1115 } 1213 1116 1117 + static bool lpc_ich_lpt_set_writeable(void __iomem *base, void *data) 1118 + { 1119 + struct pci_dev *pdev = data; 1120 + 1121 + return lpc_ich_set_writeable(pdev->bus, pdev->devfn); 1122 + } 1123 + 1214 1124 static bool lpc_ich_bxt_set_writeable(void __iomem *base, void *data) 1215 1125 { 1216 - unsigned int spi = PCI_DEVFN(13, 2); 1217 - struct pci_bus *bus = data; 1218 - u32 bcr; 1126 + struct pci_dev *pdev = data; 1219 1127 1220 - pci_bus_read_config_dword(bus, spi, BCR, &bcr); 1221 - if (!(bcr & BCR_WPD)) { 1222 - bcr |= BCR_WPD; 1223 - pci_bus_write_config_dword(bus, spi, BCR, bcr); 1224 - pci_bus_read_config_dword(bus, spi, BCR, &bcr); 1225 - } 1226 - 1227 - return bcr & BCR_WPD; 1128 + return lpc_ich_set_writeable(pdev->bus, PCI_DEVFN(13, 2)); 1228 1129 } 1229 1130 1230 1131 static int lpc_ich_init_spi(struct pci_dev *dev) ··· 1230 1137 struct resource *res = &intel_spi_res[0]; 1231 1138 struct intel_spi_boardinfo *info; 1232 1139 u32 spi_base, rcba; 1140 + int ret; 1233 1141 1234 1142 info = devm_kzalloc(&dev->dev, sizeof(*info), GFP_KERNEL); 1235 1143 if (!info) ··· 1261 1167 } 1262 1168 break; 1263 1169 1264 - case INTEL_SPI_BXT: { 1265 - unsigned int p2sb = PCI_DEVFN(13, 0); 1266 - unsigned int spi = PCI_DEVFN(13, 2); 1267 - struct pci_bus *bus = dev->bus; 1268 - 1170 + case INTEL_SPI_BXT: 1269 1171 /* 1270 1172 * The P2SB is hidden by BIOS and we need to unhide it in 1271 1173 * order to read BAR of the SPI flash device. Once that is 1272 1174 * done we hide it again. 1273 1175 */ 1274 - pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x0); 1275 - pci_bus_read_config_dword(bus, spi, PCI_BASE_ADDRESS_0, 1276 - &spi_base); 1277 - if (spi_base != ~0) { 1278 - res->start = spi_base & 0xfffffff0; 1279 - res->end = res->start + SPIBASE_APL_SZ - 1; 1176 + ret = p2sb_bar(dev->bus, PCI_DEVFN(13, 2), res); 1177 + if (ret) 1178 + return ret; 1280 1179 1281 - info->set_writeable = lpc_ich_bxt_set_writeable; 1282 - info->data = bus; 1283 - } 1284 - 1285 - pci_bus_write_config_byte(bus, p2sb, 0xe1, 0x1); 1180 + info->set_writeable = lpc_ich_bxt_set_writeable; 1181 + info->data = dev; 1286 1182 break; 1287 - } 1288 1183 1289 1184 default: 1290 1185 return -EINVAL; ··· 1328 1245 1329 1246 if (lpc_chipset_info[priv->chipset].gpio_version) { 1330 1247 ret = lpc_ich_init_gpio(dev); 1248 + if (!ret) 1249 + cell_added = true; 1250 + } 1251 + 1252 + if (priv->chipset == LPC_APL) { 1253 + ret = lpc_ich_init_pinctrl(dev); 1331 1254 if (!ret) 1332 1255 cell_added = true; 1333 1256 }
+6 -8
drivers/pinctrl/intel/pinctrl-intel.c
··· 1641 1641 1642 1642 const struct intel_pinctrl_soc_data *intel_pinctrl_get_soc_data(struct platform_device *pdev) 1643 1643 { 1644 + const struct intel_pinctrl_soc_data * const *table; 1644 1645 const struct intel_pinctrl_soc_data *data = NULL; 1645 - const struct intel_pinctrl_soc_data **table; 1646 - struct acpi_device *adev; 1647 - unsigned int i; 1648 1646 1649 - adev = ACPI_COMPANION(&pdev->dev); 1650 - if (adev) { 1651 - const void *match = device_get_match_data(&pdev->dev); 1647 + table = device_get_match_data(&pdev->dev); 1648 + if (table) { 1649 + struct acpi_device *adev = ACPI_COMPANION(&pdev->dev); 1650 + unsigned int i; 1652 1651 1653 - table = (const struct intel_pinctrl_soc_data **)match; 1654 1652 for (i = 0; table[i]; i++) { 1655 1653 if (!strcmp(adev->pnp.unique_id, table[i]->uid)) { 1656 1654 data = table[i]; ··· 1662 1664 if (!id) 1663 1665 return ERR_PTR(-ENODEV); 1664 1666 1665 - table = (const struct intel_pinctrl_soc_data **)id->driver_data; 1667 + table = (const struct intel_pinctrl_soc_data * const *)id->driver_data; 1666 1668 data = table[pdev->id]; 1667 1669 } 1668 1670
+12
drivers/platform/x86/intel/Kconfig
··· 70 70 enable/disable the Camera, WiFi, BT etc. devices. If in doubt, say Y 71 71 here; it will only load on supported platforms. 72 72 73 + config P2SB 74 + bool "Primary to Sideband (P2SB) bridge access support" 75 + depends on PCI 76 + help 77 + The Primary to Sideband (P2SB) bridge is an interface to some 78 + PCI devices connected through it. In particular, SPI NOR controller 79 + in Intel Apollo Lake SoC is one of such devices. 80 + 81 + The main purpose of this library is to unhide P2SB device in case 82 + firmware kept it hidden on some platforms in order to access devices 83 + behind it. 84 + 73 85 config INTEL_BXTWC_PMIC_TMU 74 86 tristate "Intel Broxton Whiskey Cove TMU Driver" 75 87 depends on INTEL_SOC_PMIC_BXTWC
+2
drivers/platform/x86/intel/Makefile
··· 28 28 obj-$(CONFIG_INTEL_INT0002_VGPIO) += intel_int0002_vgpio.o 29 29 intel_oaktrail-y := oaktrail.o 30 30 obj-$(CONFIG_INTEL_OAKTRAIL) += intel_oaktrail.o 31 + intel_p2sb-y := p2sb.o 32 + obj-$(CONFIG_P2SB) += intel_p2sb.o 31 33 intel_sdsi-y := sdsi.o 32 34 obj-$(CONFIG_INTEL_SDSI) += intel_sdsi.o 33 35 intel_vsec-y := vsec.o
+133
drivers/platform/x86/intel/p2sb.c
··· 1 + // SPDX-License-Identifier: GPL-2.0 2 + /* 3 + * Primary to Sideband (P2SB) bridge access support 4 + * 5 + * Copyright (c) 2017, 2021-2022 Intel Corporation. 6 + * 7 + * Authors: Andy Shevchenko <andriy.shevchenko@linux.intel.com> 8 + * Jonathan Yong <jonathan.yong@intel.com> 9 + */ 10 + 11 + #include <linux/bits.h> 12 + #include <linux/export.h> 13 + #include <linux/pci.h> 14 + #include <linux/platform_data/x86/p2sb.h> 15 + 16 + #include <asm/cpu_device_id.h> 17 + #include <asm/intel-family.h> 18 + 19 + #define P2SBC 0xe0 20 + #define P2SBC_HIDE BIT(8) 21 + 22 + static const struct x86_cpu_id p2sb_cpu_ids[] = { 23 + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT, PCI_DEVFN(13, 0)), 24 + X86_MATCH_INTEL_FAM6_MODEL(ATOM_GOLDMONT_D, PCI_DEVFN(31, 1)), 25 + X86_MATCH_INTEL_FAM6_MODEL(ATOM_SILVERMONT_D, PCI_DEVFN(31, 1)), 26 + X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE, PCI_DEVFN(31, 1)), 27 + X86_MATCH_INTEL_FAM6_MODEL(KABYLAKE_L, PCI_DEVFN(31, 1)), 28 + X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE, PCI_DEVFN(31, 1)), 29 + X86_MATCH_INTEL_FAM6_MODEL(SKYLAKE_L, PCI_DEVFN(31, 1)), 30 + {} 31 + }; 32 + 33 + static int p2sb_get_devfn(unsigned int *devfn) 34 + { 35 + const struct x86_cpu_id *id; 36 + 37 + id = x86_match_cpu(p2sb_cpu_ids); 38 + if (!id) 39 + return -ENODEV; 40 + 41 + *devfn = (unsigned int)id->driver_data; 42 + return 0; 43 + } 44 + 45 + static int p2sb_read_bar0(struct pci_dev *pdev, struct resource *mem) 46 + { 47 + /* Copy resource from the first BAR of the device in question */ 48 + *mem = pdev->resource[0]; 49 + return 0; 50 + } 51 + 52 + static int p2sb_scan_and_read(struct pci_bus *bus, unsigned int devfn, struct resource *mem) 53 + { 54 + struct pci_dev *pdev; 55 + int ret; 56 + 57 + pdev = pci_scan_single_device(bus, devfn); 58 + if (!pdev) 59 + return -ENODEV; 60 + 61 + ret = p2sb_read_bar0(pdev, mem); 62 + 63 + pci_stop_and_remove_bus_device(pdev); 64 + return ret; 65 + } 66 + 67 + /** 68 + * p2sb_bar - Get Primary to Sideband (P2SB) bridge device BAR 69 + * @bus: PCI bus to communicate with 70 + * @devfn: PCI slot and function to communicate with 71 + * @mem: memory resource to be filled in 72 + * 73 + * The BIOS prevents the P2SB device from being enumerated by the PCI 74 + * subsystem, so we need to unhide and hide it back to lookup the BAR. 75 + * 76 + * if @bus is NULL, the bus 0 in domain 0 will be used. 77 + * If @devfn is 0, it will be replaced by devfn of the P2SB device. 78 + * 79 + * Caller must provide a valid pointer to @mem. 80 + * 81 + * Locking is handled by pci_rescan_remove_lock mutex. 82 + * 83 + * Return: 84 + * 0 on success or appropriate errno value on error. 85 + */ 86 + int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) 87 + { 88 + struct pci_dev *pdev_p2sb; 89 + unsigned int devfn_p2sb; 90 + u32 value = P2SBC_HIDE; 91 + int ret; 92 + 93 + /* Get devfn for P2SB device itself */ 94 + ret = p2sb_get_devfn(&devfn_p2sb); 95 + if (ret) 96 + return ret; 97 + 98 + /* if @bus is NULL, use bus 0 in domain 0 */ 99 + bus = bus ?: pci_find_bus(0, 0); 100 + 101 + /* 102 + * Prevent concurrent PCI bus scan from seeing the P2SB device and 103 + * removing via sysfs while it is temporarily exposed. 104 + */ 105 + pci_lock_rescan_remove(); 106 + 107 + /* Unhide the P2SB device, if needed */ 108 + pci_bus_read_config_dword(bus, devfn_p2sb, P2SBC, &value); 109 + if (value & P2SBC_HIDE) 110 + pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, 0); 111 + 112 + pdev_p2sb = pci_scan_single_device(bus, devfn_p2sb); 113 + if (devfn) 114 + ret = p2sb_scan_and_read(bus, devfn, mem); 115 + else 116 + ret = p2sb_read_bar0(pdev_p2sb, mem); 117 + pci_stop_and_remove_bus_device(pdev_p2sb); 118 + 119 + /* Hide the P2SB device, if it was hidden */ 120 + if (value & P2SBC_HIDE) 121 + pci_bus_write_config_dword(bus, devfn_p2sb, P2SBC, P2SBC_HIDE); 122 + 123 + pci_unlock_rescan_remove(); 124 + 125 + if (ret) 126 + return ret; 127 + 128 + if (mem->flags == 0) 129 + return -ENODEV; 130 + 131 + return 0; 132 + } 133 + EXPORT_SYMBOL_GPL(p2sb_bar);
+4 -39
drivers/platform/x86/simatic-ipc.c
··· 51 51 { 52 52 u8 ledmode = SIMATIC_IPC_DEVICE_NONE; 53 53 u8 wdtmode = SIMATIC_IPC_DEVICE_NONE; 54 + char *pdevname = KBUILD_MODNAME "_leds"; 54 55 int i; 55 56 56 57 platform_data.devmode = SIMATIC_IPC_DEVICE_NONE; ··· 65 64 } 66 65 67 66 if (ledmode != SIMATIC_IPC_DEVICE_NONE) { 67 + if (ledmode == SIMATIC_IPC_DEVICE_127E) 68 + pdevname = KBUILD_MODNAME "_leds_gpio"; 68 69 platform_data.devmode = ledmode; 69 70 ipc_led_platform_device = 70 71 platform_device_register_data(NULL, 71 - KBUILD_MODNAME "_leds", PLATFORM_DEVID_NONE, 72 + pdevname, PLATFORM_DEVID_NONE, 72 73 &platform_data, 73 74 sizeof(struct simatic_ipc_platform)); 74 75 if (IS_ERR(ipc_led_platform_device)) ··· 103 100 104 101 return 0; 105 102 } 106 - 107 - /* FIXME: this should eventually be done with generic P2SB discovery code 108 - * the individual drivers for watchdogs and LEDs access memory that implements 109 - * GPIO, but pinctrl will not come up because of missing ACPI entries 110 - * 111 - * While there is no conflict a cleaner solution would be to somehow bring up 112 - * pinctrl even with these ACPI entries missing, and base the drivers on pinctrl. 113 - * After which the following function could be dropped, together with the code 114 - * poking the memory. 115 - */ 116 - /* 117 - * Get membase address from PCI, used in leds and wdt module. Here we read 118 - * the bar0. The final address calculation is done in the appropriate modules 119 - */ 120 - u32 simatic_ipc_get_membase0(unsigned int p2sb) 121 - { 122 - struct pci_bus *bus; 123 - u32 bar0 = 0; 124 - /* 125 - * The GPIO memory is in bar0 of the hidden P2SB device. 126 - * Unhide the device to have a quick look at it, before we hide it 127 - * again. 128 - * Also grab the pci rescan lock so that device does not get discovered 129 - * and remapped while it is visible. 130 - * This code is inspired by drivers/mfd/lpc_ich.c 131 - */ 132 - bus = pci_find_bus(0, 0); 133 - pci_lock_rescan_remove(); 134 - pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x0); 135 - pci_bus_read_config_dword(bus, p2sb, PCI_BASE_ADDRESS_0, &bar0); 136 - 137 - bar0 &= ~0xf; 138 - pci_bus_write_config_byte(bus, p2sb, 0xE1, 0x1); 139 - pci_unlock_rescan_remove(); 140 - 141 - return bar0; 142 - } 143 - EXPORT_SYMBOL(simatic_ipc_get_membase0); 144 103 145 104 static int __init simatic_ipc_init_module(void) 146 105 {
+48 -24
drivers/soc/bcm/bcm2835-power.c
··· 126 126 127 127 #define ASB_AXI_BRDG_ID 0x20 128 128 129 - #define ASB_READ(reg) readl(power->asb + (reg)) 130 - #define ASB_WRITE(reg, val) writel(PM_PASSWORD | (val), power->asb + (reg)) 129 + #define BCM2835_BRDG_ID 0x62726467 131 130 132 131 struct bcm2835_power_domain { 133 132 struct generic_pm_domain base; ··· 141 142 void __iomem *base; 142 143 /* AXI Async bridge registers. */ 143 144 void __iomem *asb; 145 + /* RPiVid bridge registers. */ 146 + void __iomem *rpivid_asb; 144 147 145 148 struct genpd_onecell_data pd_xlate; 146 149 struct bcm2835_power_domain domains[BCM2835_POWER_DOMAIN_COUNT]; 147 150 struct reset_controller_dev reset; 148 151 }; 149 152 150 - static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg) 153 + static int bcm2835_asb_control(struct bcm2835_power *power, u32 reg, bool enable) 151 154 { 155 + void __iomem *base = power->asb; 152 156 u64 start; 157 + u32 val; 153 158 154 - if (!reg) 159 + switch (reg) { 160 + case 0: 155 161 return 0; 162 + case ASB_V3D_S_CTRL: 163 + case ASB_V3D_M_CTRL: 164 + if (power->rpivid_asb) 165 + base = power->rpivid_asb; 166 + break; 167 + } 156 168 157 169 start = ktime_get_ns(); 158 170 159 171 /* Enable the module's async AXI bridges. */ 160 - ASB_WRITE(reg, ASB_READ(reg) & ~ASB_REQ_STOP); 161 - while (ASB_READ(reg) & ASB_ACK) { 172 + if (enable) { 173 + val = readl(base + reg) & ~ASB_REQ_STOP; 174 + } else { 175 + val = readl(base + reg) | ASB_REQ_STOP; 176 + } 177 + writel(PM_PASSWORD | val, base + reg); 178 + 179 + while (readl(base + reg) & ASB_ACK) { 162 180 cpu_relax(); 163 181 if (ktime_get_ns() - start >= 1000) 164 182 return -ETIMEDOUT; ··· 184 168 return 0; 185 169 } 186 170 171 + static int bcm2835_asb_enable(struct bcm2835_power *power, u32 reg) 172 + { 173 + return bcm2835_asb_control(power, reg, true); 174 + } 175 + 187 176 static int bcm2835_asb_disable(struct bcm2835_power *power, u32 reg) 188 177 { 189 - u64 start; 190 - 191 - if (!reg) 192 - return 0; 193 - 194 - start = ktime_get_ns(); 195 - 196 - /* Enable the module's async AXI bridges. */ 197 - ASB_WRITE(reg, ASB_READ(reg) | ASB_REQ_STOP); 198 - while (!(ASB_READ(reg) & ASB_ACK)) { 199 - cpu_relax(); 200 - if (ktime_get_ns() - start >= 1000) 201 - return -ETIMEDOUT; 202 - } 203 - 204 - return 0; 178 + return bcm2835_asb_control(power, reg, false); 205 179 } 206 180 207 181 static int bcm2835_power_power_off(struct bcm2835_power_domain *pd, u32 pm_reg) 208 182 { 209 183 struct bcm2835_power *power = pd->power; 184 + 185 + /* We don't run this on BCM2711 */ 186 + if (power->rpivid_asb) 187 + return 0; 210 188 211 189 /* Enable functional isolation */ 212 190 PM_WRITE(pm_reg, PM_READ(pm_reg) & ~PM_ISFUNC); ··· 222 212 int ret; 223 213 int inrush; 224 214 bool powok; 215 + 216 + /* We don't run this on BCM2711 */ 217 + if (power->rpivid_asb) 218 + return 0; 225 219 226 220 /* If it was already powered on by the fw, leave it that way. */ 227 221 if (PM_READ(pm_reg) & PM_POWUP) ··· 640 626 power->dev = dev; 641 627 power->base = pm->base; 642 628 power->asb = pm->asb; 629 + power->rpivid_asb = pm->rpivid_asb; 643 630 644 - id = ASB_READ(ASB_AXI_BRDG_ID); 645 - if (id != 0x62726467 /* "BRDG" */) { 631 + id = readl(power->asb + ASB_AXI_BRDG_ID); 632 + if (id != BCM2835_BRDG_ID /* "BRDG" */) { 646 633 dev_err(dev, "ASB register ID returned 0x%08x\n", id); 647 634 return -ENODEV; 635 + } 636 + 637 + if (power->rpivid_asb) { 638 + id = readl(power->rpivid_asb + ASB_AXI_BRDG_ID); 639 + if (id != BCM2835_BRDG_ID /* "BRDG" */) { 640 + dev_err(dev, "RPiVid ASB register ID returned 0x%08x\n", 641 + id); 642 + return -ENODEV; 643 + } 648 644 } 649 645 650 646 power->pd_xlate.domains = devm_kcalloc(dev,
+1
drivers/watchdog/Kconfig
··· 1647 1647 tristate "Siemens Simatic IPC Watchdog" 1648 1648 depends on SIEMENS_SIMATIC_IPC 1649 1649 select WATCHDOG_CORE 1650 + select P2SB 1650 1651 help 1651 1652 This driver adds support for several watchdogs found in Industrial 1652 1653 PCs from Siemens.
+8 -7
drivers/watchdog/simatic-ipc-wdt.c
··· 16 16 #include <linux/kernel.h> 17 17 #include <linux/module.h> 18 18 #include <linux/pci.h> 19 + #include <linux/platform_data/x86/p2sb.h> 19 20 #include <linux/platform_data/x86/simatic-ipc-base.h> 20 21 #include <linux/platform_device.h> 21 22 #include <linux/sizes.h> ··· 55 54 DEFINE_RES_IO_NAMED(WD_TRIGGER_IOADR, SZ_1, 56 55 KBUILD_MODNAME " WD_TRIGGER_IOADR"); 57 56 58 - /* the actual start will be discovered with pci, 0 is a placeholder */ 57 + /* the actual start will be discovered with p2sb, 0 is a placeholder */ 59 58 static struct resource mem_resource = 60 - DEFINE_RES_MEM_NAMED(0, SZ_4, "WD_RESET_BASE_ADR"); 59 + DEFINE_RES_MEM_NAMED(0, 0, "WD_RESET_BASE_ADR"); 61 60 62 61 static u32 wd_timeout_table[] = {2, 4, 6, 8, 16, 32, 48, 64 }; 63 62 static void __iomem *wd_reset_base_addr; ··· 151 150 struct simatic_ipc_platform *plat = pdev->dev.platform_data; 152 151 struct device *dev = &pdev->dev; 153 152 struct resource *res; 153 + int ret; 154 154 155 155 switch (plat->devmode) { 156 156 case SIMATIC_IPC_DEVICE_227E: ··· 192 190 if (plat->devmode == SIMATIC_IPC_DEVICE_427E) { 193 191 res = &mem_resource; 194 192 195 - /* get GPIO base from PCI */ 196 - res->start = simatic_ipc_get_membase0(PCI_DEVFN(0x1f, 1)); 197 - if (res->start == 0) 198 - return -ENODEV; 193 + ret = p2sb_bar(NULL, 0, res); 194 + if (ret) 195 + return ret; 199 196 200 197 /* do the final address calculation */ 201 198 res->start = res->start + (GPIO_COMMUNITY0_PORT_ID << 16) + 202 199 PAD_CFG_DW0_GPP_A_23; 203 - res->end += res->start; 200 + res->end = res->start + SZ_4 - 1; 204 201 205 202 wd_reset_base_addr = devm_ioremap_resource(dev, res); 206 203 if (IS_ERR(wd_reset_base_addr))
+1
include/linux/mfd/bcm2835-pm.h
··· 9 9 struct device *dev; 10 10 void __iomem *base; 11 11 void __iomem *asb; 12 + void __iomem *rpivid_asb; 12 13 }; 13 14 14 15 #endif /* BCM2835_MFD_PM_H */
+28
include/linux/platform_data/x86/p2sb.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0 */ 2 + /* 3 + * Primary to Sideband (P2SB) bridge access support 4 + */ 5 + 6 + #ifndef _PLATFORM_DATA_X86_P2SB_H 7 + #define _PLATFORM_DATA_X86_P2SB_H 8 + 9 + #include <linux/errno.h> 10 + #include <linux/kconfig.h> 11 + 12 + struct pci_bus; 13 + struct resource; 14 + 15 + #if IS_BUILTIN(CONFIG_P2SB) 16 + 17 + int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem); 18 + 19 + #else /* CONFIG_P2SB */ 20 + 21 + static inline int p2sb_bar(struct pci_bus *bus, unsigned int devfn, struct resource *mem) 22 + { 23 + return -ENODEV; 24 + } 25 + 26 + #endif /* CONFIG_P2SB is not set */ 27 + 28 + #endif /* _PLATFORM_DATA_X86_P2SB_H */
-2
include/linux/platform_data/x86/simatic-ipc-base.h
··· 24 24 u8 devmode; 25 25 }; 26 26 27 - u32 simatic_ipc_get_membase0(unsigned int p2sb); 28 - 29 27 #endif /* __PLATFORM_DATA_X86_SIMATIC_IPC_BASE_H */