1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Driver for the Intel Broxton PMC 4 * 5 * (C) Copyright 2014 - 2020 Intel Corporation 6 * 7 * This driver is based on Intel SCU IPC driver (intel_scu_ipc.c) by 8 * Sreedhara DS <sreedhara.ds@intel.com> 9 * 10 * The PMC (Power Management Controller) running on the ARC processor 11 * communicates with another entity running in the IA (Intel Architecture) 12 * core through an IPC (Intel Processor Communications) mechanism which in 13 * turn sends messages between the IA and the PMC. 14 */ 15 16 #include <linux/acpi.h> 17 #include <linux/delay.h> 18 #include <linux/errno.h> 19 #include <linux/interrupt.h> 20 #include <linux/io-64-nonatomic-lo-hi.h> 21 #include <linux/mfd/core.h> 22 #include <linux/mfd/intel_pmc_bxt.h> 23 #include <linux/module.h> 24 #include <linux/platform_device.h> 25 #include <linux/platform_data/itco_wdt.h> 26 #include <linux/platform_data/x86/intel_scu_ipc.h> 27 28 /* Residency with clock rate at 19.2MHz to usecs */ 29 #define S0IX_RESIDENCY_IN_USECS(d, s) \ 30 ({ \ 31 u64 result = 10ull * ((d) + (s)); \ 32 do_div(result, 192); \ 33 result; \ 34 }) 35 36 /* Resources exported from IFWI */ 37 #define PLAT_RESOURCE_IPC_INDEX 0 38 #define PLAT_RESOURCE_IPC_SIZE 0x1000 39 #define PLAT_RESOURCE_GCR_OFFSET 0x1000 40 #define PLAT_RESOURCE_GCR_SIZE 0x1000 41 #define PLAT_RESOURCE_BIOS_DATA_INDEX 1 42 #define PLAT_RESOURCE_BIOS_IFACE_INDEX 2 43 #define PLAT_RESOURCE_TELEM_SSRAM_INDEX 3 44 #define PLAT_RESOURCE_ISP_DATA_INDEX 4 45 #define PLAT_RESOURCE_ISP_IFACE_INDEX 5 46 #define PLAT_RESOURCE_GTD_DATA_INDEX 6 47 #define PLAT_RESOURCE_GTD_IFACE_INDEX 7 48 #define PLAT_RESOURCE_ACPI_IO_INDEX 0 49 50 /* 51 * BIOS does not create an ACPI device for each PMC function, but 52 * exports multiple resources from one ACPI device (IPC) for multiple 53 * functions. This driver is responsible for creating a child device and 54 * to export resources for those functions. 55 */ 56 #define SMI_EN_OFFSET 0x0040 57 #define SMI_EN_SIZE 4 58 #define TCO_BASE_OFFSET 0x0060 59 #define TCO_REGS_SIZE 16 60 #define TELEM_SSRAM_SIZE 240 61 #define TELEM_PMC_SSRAM_OFFSET 0x1b00 62 #define TELEM_PUNIT_SSRAM_OFFSET 0x1a00 63 64 /* Commands */ 65 #define PMC_NORTHPEAK_CTRL 0xed 66 67 static inline bool is_gcr_valid(u32 offset) 68 { 69 return offset < PLAT_RESOURCE_GCR_SIZE - 8; 70 } 71 72 /** 73 * intel_pmc_gcr_read64() - Read a 64-bit PMC GCR register 74 * @pmc: PMC device pointer 75 * @offset: offset of GCR register from GCR address base 76 * @data: data pointer for storing the register output 77 * 78 * Reads the 64-bit PMC GCR register at given offset. 79 * 80 * Return: Negative value on error or 0 on success. 81 */ 82 int intel_pmc_gcr_read64(struct intel_pmc_dev *pmc, u32 offset, u64 *data) 83 { 84 if (!is_gcr_valid(offset)) 85 return -EINVAL; 86 87 spin_lock(&pmc->gcr_lock); 88 *data = readq(pmc->gcr_mem_base + offset); 89 spin_unlock(&pmc->gcr_lock); 90 91 return 0; 92 } 93 EXPORT_SYMBOL_GPL(intel_pmc_gcr_read64); 94 95 /** 96 * intel_pmc_gcr_update() - Update PMC GCR register bits 97 * @pmc: PMC device pointer 98 * @offset: offset of GCR register from GCR address base 99 * @mask: bit mask for update operation 100 * @val: update value 101 * 102 * Updates the bits of given GCR register as specified by 103 * @mask and @val. 104 * 105 * Return: Negative value on error or 0 on success. 106 */ 107 int intel_pmc_gcr_update(struct intel_pmc_dev *pmc, u32 offset, u32 mask, u32 val) 108 { 109 u32 new_val; 110 111 if (!is_gcr_valid(offset)) 112 return -EINVAL; 113 114 spin_lock(&pmc->gcr_lock); 115 new_val = readl(pmc->gcr_mem_base + offset); 116 117 new_val = (new_val & ~mask) | (val & mask); 118 writel(new_val, pmc->gcr_mem_base + offset); 119 120 new_val = readl(pmc->gcr_mem_base + offset); 121 spin_unlock(&pmc->gcr_lock); 122 123 /* Check whether the bit update is successful */ 124 return (new_val & mask) != (val & mask) ? -EIO : 0; 125 } 126 EXPORT_SYMBOL_GPL(intel_pmc_gcr_update); 127 128 /** 129 * intel_pmc_s0ix_counter_read() - Read S0ix residency 130 * @pmc: PMC device pointer 131 * @data: Out param that contains current S0ix residency count. 132 * 133 * Writes to @data how many usecs the system has been in low-power S0ix 134 * state. 135 * 136 * Return: An error code or 0 on success. 137 */ 138 int intel_pmc_s0ix_counter_read(struct intel_pmc_dev *pmc, u64 *data) 139 { 140 u64 deep, shlw; 141 142 spin_lock(&pmc->gcr_lock); 143 deep = readq(pmc->gcr_mem_base + PMC_GCR_TELEM_DEEP_S0IX_REG); 144 shlw = readq(pmc->gcr_mem_base + PMC_GCR_TELEM_SHLW_S0IX_REG); 145 spin_unlock(&pmc->gcr_lock); 146 147 *data = S0IX_RESIDENCY_IN_USECS(deep, shlw); 148 return 0; 149 } 150 EXPORT_SYMBOL_GPL(intel_pmc_s0ix_counter_read); 151 152 /** 153 * simplecmd_store() - Send a simple IPC command 154 * @dev: Device under the attribute is 155 * @attr: Attribute in question 156 * @buf: Buffer holding data to be stored to the attribute 157 * @count: Number of bytes in @buf 158 * 159 * Expects a string with two integers separated with space. These two 160 * values hold command and subcommand that is send to PMC. 161 * 162 * Return: Number number of bytes written (@count) or negative errno in 163 * case of error. 164 */ 165 static ssize_t simplecmd_store(struct device *dev, struct device_attribute *attr, 166 const char *buf, size_t count) 167 { 168 struct intel_pmc_dev *pmc = dev_get_drvdata(dev); 169 struct intel_scu_ipc_dev *scu = pmc->scu; 170 int subcmd; 171 int cmd; 172 int ret; 173 174 ret = sscanf(buf, "%d %d", &cmd, &subcmd); 175 if (ret != 2) { 176 dev_err(dev, "Invalid values, expected: cmd subcmd\n"); 177 return -EINVAL; 178 } 179 180 ret = intel_scu_ipc_dev_simple_command(scu, cmd, subcmd); 181 if (ret) 182 return ret; 183 184 return count; 185 } 186 static DEVICE_ATTR_WO(simplecmd); 187 188 /** 189 * northpeak_store() - Enable or disable Northpeak 190 * @dev: Device under the attribute is 191 * @attr: Attribute in question 192 * @buf: Buffer holding data to be stored to the attribute 193 * @count: Number of bytes in @buf 194 * 195 * Expects an unsigned integer. Non-zero enables Northpeak and zero 196 * disables it. 197 * 198 * Return: Number number of bytes written (@count) or negative errno in 199 * case of error. 200 */ 201 static ssize_t northpeak_store(struct device *dev, struct device_attribute *attr, 202 const char *buf, size_t count) 203 { 204 struct intel_pmc_dev *pmc = dev_get_drvdata(dev); 205 struct intel_scu_ipc_dev *scu = pmc->scu; 206 unsigned long val; 207 int subcmd; 208 int ret; 209 210 ret = kstrtoul(buf, 0, &val); 211 if (ret) 212 return ret; 213 214 /* Northpeak is enabled if subcmd == 1 and disabled if it is 0 */ 215 if (val) 216 subcmd = 1; 217 else 218 subcmd = 0; 219 220 ret = intel_scu_ipc_dev_simple_command(scu, PMC_NORTHPEAK_CTRL, subcmd); 221 if (ret) 222 return ret; 223 224 return count; 225 } 226 static DEVICE_ATTR_WO(northpeak); 227 228 static struct attribute *intel_pmc_attrs[] = { 229 &dev_attr_northpeak.attr, 230 &dev_attr_simplecmd.attr, 231 NULL 232 }; 233 234 static const struct attribute_group intel_pmc_group = { 235 .attrs = intel_pmc_attrs, 236 }; 237 238 static const struct attribute_group *intel_pmc_groups[] = { 239 &intel_pmc_group, 240 NULL 241 }; 242 243 static struct resource punit_res[6]; 244 245 static struct mfd_cell punit = { 246 .name = "intel_punit_ipc", 247 .resources = punit_res, 248 }; 249 250 static struct itco_wdt_platform_data tco_pdata = { 251 .name = "Apollo Lake SoC", 252 .version = 5, 253 .no_reboot_use_pmc = true, 254 }; 255 256 static struct resource tco_res[2]; 257 258 static const struct mfd_cell tco = { 259 .name = "iTCO_wdt", 260 .ignore_resource_conflicts = true, 261 .resources = tco_res, 262 .num_resources = ARRAY_SIZE(tco_res), 263 .platform_data = &tco_pdata, 264 .pdata_size = sizeof(tco_pdata), 265 }; 266 267 static const struct resource telem_res[] = { 268 DEFINE_RES_MEM(TELEM_PUNIT_SSRAM_OFFSET, TELEM_SSRAM_SIZE), 269 DEFINE_RES_MEM(TELEM_PMC_SSRAM_OFFSET, TELEM_SSRAM_SIZE), 270 }; 271 272 static const struct mfd_cell telem = { 273 .name = "intel_telemetry", 274 .resources = telem_res, 275 .num_resources = ARRAY_SIZE(telem_res), 276 }; 277 278 static int intel_pmc_get_tco_resources(struct platform_device *pdev) 279 { 280 struct resource *res; 281 282 if (acpi_has_watchdog()) 283 return 0; 284 285 res = platform_get_resource(pdev, IORESOURCE_IO, 286 PLAT_RESOURCE_ACPI_IO_INDEX); 287 if (!res) { 288 dev_err(&pdev->dev, "Failed to get IO resource\n"); 289 return -EINVAL; 290 } 291 292 tco_res[0].flags = IORESOURCE_IO; 293 tco_res[0].start = res->start + TCO_BASE_OFFSET; 294 tco_res[0].end = tco_res[0].start + TCO_REGS_SIZE - 1; 295 tco_res[1].flags = IORESOURCE_IO; 296 tco_res[1].start = res->start + SMI_EN_OFFSET; 297 tco_res[1].end = tco_res[1].start + SMI_EN_SIZE - 1; 298 299 return 0; 300 } 301 302 static int intel_pmc_get_resources(struct platform_device *pdev, 303 struct intel_pmc_dev *pmc, 304 struct intel_scu_ipc_data *scu_data) 305 { 306 struct resource gcr_res; 307 size_t npunit_res = 0; 308 struct resource *res; 309 int ret; 310 311 scu_data->irq = platform_get_irq_optional(pdev, 0); 312 313 res = platform_get_resource(pdev, IORESOURCE_MEM, 314 PLAT_RESOURCE_IPC_INDEX); 315 if (!res) { 316 dev_err(&pdev->dev, "Failed to get IPC resource\n"); 317 return -EINVAL; 318 } 319 320 /* IPC registers */ 321 scu_data->mem.flags = res->flags; 322 scu_data->mem.start = res->start; 323 scu_data->mem.end = res->start + PLAT_RESOURCE_IPC_SIZE - 1; 324 325 /* GCR registers */ 326 gcr_res.flags = res->flags; 327 gcr_res.start = res->start + PLAT_RESOURCE_GCR_OFFSET; 328 gcr_res.end = gcr_res.start + PLAT_RESOURCE_GCR_SIZE - 1; 329 330 pmc->gcr_mem_base = devm_ioremap_resource(&pdev->dev, &gcr_res); 331 if (IS_ERR(pmc->gcr_mem_base)) 332 return PTR_ERR(pmc->gcr_mem_base); 333 334 /* Only register iTCO watchdog if there is no WDAT ACPI table */ 335 ret = intel_pmc_get_tco_resources(pdev); 336 if (ret) 337 return ret; 338 339 /* BIOS data register */ 340 res = platform_get_resource(pdev, IORESOURCE_MEM, 341 PLAT_RESOURCE_BIOS_DATA_INDEX); 342 if (!res) { 343 dev_err(&pdev->dev, "Failed to get resource of P-unit BIOS data\n"); 344 return -EINVAL; 345 } 346 punit_res[npunit_res++] = *res; 347 348 /* BIOS interface register */ 349 res = platform_get_resource(pdev, IORESOURCE_MEM, 350 PLAT_RESOURCE_BIOS_IFACE_INDEX); 351 if (!res) { 352 dev_err(&pdev->dev, "Failed to get resource of P-unit BIOS interface\n"); 353 return -EINVAL; 354 } 355 punit_res[npunit_res++] = *res; 356 357 /* ISP data register, optional */ 358 res = platform_get_resource(pdev, IORESOURCE_MEM, 359 PLAT_RESOURCE_ISP_DATA_INDEX); 360 if (res) 361 punit_res[npunit_res++] = *res; 362 363 /* ISP interface register, optional */ 364 res = platform_get_resource(pdev, IORESOURCE_MEM, 365 PLAT_RESOURCE_ISP_IFACE_INDEX); 366 if (res) 367 punit_res[npunit_res++] = *res; 368 369 /* GTD data register, optional */ 370 res = platform_get_resource(pdev, IORESOURCE_MEM, 371 PLAT_RESOURCE_GTD_DATA_INDEX); 372 if (res) 373 punit_res[npunit_res++] = *res; 374 375 /* GTD interface register, optional */ 376 res = platform_get_resource(pdev, IORESOURCE_MEM, 377 PLAT_RESOURCE_GTD_IFACE_INDEX); 378 if (res) 379 punit_res[npunit_res++] = *res; 380 381 punit.num_resources = npunit_res; 382 383 /* Telemetry SSRAM is optional */ 384 res = platform_get_resource(pdev, IORESOURCE_MEM, 385 PLAT_RESOURCE_TELEM_SSRAM_INDEX); 386 if (res) 387 pmc->telem_base = res; 388 389 return 0; 390 } 391 392 static int intel_pmc_create_devices(struct intel_pmc_dev *pmc) 393 { 394 int ret; 395 396 if (!acpi_has_watchdog()) { 397 ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, &tco, 398 1, NULL, 0, NULL); 399 if (ret) 400 return ret; 401 } 402 403 ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, &punit, 1, 404 NULL, 0, NULL); 405 if (ret) 406 return ret; 407 408 if (pmc->telem_base) { 409 ret = devm_mfd_add_devices(pmc->dev, PLATFORM_DEVID_AUTO, 410 &telem, 1, pmc->telem_base, 0, NULL); 411 } 412 413 return ret; 414 } 415 416 static const struct acpi_device_id intel_pmc_acpi_ids[] = { 417 { "INT34D2" }, 418 { } 419 }; 420 MODULE_DEVICE_TABLE(acpi, intel_pmc_acpi_ids); 421 422 static int intel_pmc_probe(struct platform_device *pdev) 423 { 424 struct intel_scu_ipc_data scu_data = {}; 425 struct intel_pmc_dev *pmc; 426 int ret; 427 428 pmc = devm_kzalloc(&pdev->dev, sizeof(*pmc), GFP_KERNEL); 429 if (!pmc) 430 return -ENOMEM; 431 432 pmc->dev = &pdev->dev; 433 spin_lock_init(&pmc->gcr_lock); 434 435 ret = intel_pmc_get_resources(pdev, pmc, &scu_data); 436 if (ret) { 437 dev_err(&pdev->dev, "Failed to request resources\n"); 438 return ret; 439 } 440 441 pmc->scu = devm_intel_scu_ipc_register(&pdev->dev, &scu_data); 442 if (IS_ERR(pmc->scu)) 443 return PTR_ERR(pmc->scu); 444 445 platform_set_drvdata(pdev, pmc); 446 447 ret = intel_pmc_create_devices(pmc); 448 if (ret) 449 dev_err(&pdev->dev, "Failed to create PMC devices\n"); 450 451 return ret; 452 } 453 454 static struct platform_driver intel_pmc_driver = { 455 .probe = intel_pmc_probe, 456 .driver = { 457 .name = "intel_pmc_bxt", 458 .acpi_match_table = intel_pmc_acpi_ids, 459 .dev_groups = intel_pmc_groups, 460 }, 461 }; 462 module_platform_driver(intel_pmc_driver); 463 464 MODULE_AUTHOR("Mika Westerberg <mika.westerberg@linux.intel.com>"); 465 MODULE_AUTHOR("Zha Qipeng <qipeng.zha@intel.com>"); 466 MODULE_DESCRIPTION("Intel Broxton PMC driver"); 467 MODULE_LICENSE("GPL v2"); 468