18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 28c2ecf20Sopenharmony_ci/* 38c2ecf20Sopenharmony_ci * Intel Atom SOC Power Management Controller Driver 48c2ecf20Sopenharmony_ci * Copyright (c) 2014, Intel Corporation. 58c2ecf20Sopenharmony_ci */ 68c2ecf20Sopenharmony_ci 78c2ecf20Sopenharmony_ci#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 88c2ecf20Sopenharmony_ci 98c2ecf20Sopenharmony_ci#include <linux/debugfs.h> 108c2ecf20Sopenharmony_ci#include <linux/device.h> 118c2ecf20Sopenharmony_ci#include <linux/dmi.h> 128c2ecf20Sopenharmony_ci#include <linux/init.h> 138c2ecf20Sopenharmony_ci#include <linux/io.h> 148c2ecf20Sopenharmony_ci#include <linux/platform_data/x86/clk-pmc-atom.h> 158c2ecf20Sopenharmony_ci#include <linux/platform_data/x86/pmc_atom.h> 168c2ecf20Sopenharmony_ci#include <linux/platform_device.h> 178c2ecf20Sopenharmony_ci#include <linux/pci.h> 188c2ecf20Sopenharmony_ci#include <linux/seq_file.h> 198c2ecf20Sopenharmony_ci 208c2ecf20Sopenharmony_cistruct pmc_bit_map { 218c2ecf20Sopenharmony_ci const char *name; 228c2ecf20Sopenharmony_ci u32 bit_mask; 238c2ecf20Sopenharmony_ci}; 248c2ecf20Sopenharmony_ci 258c2ecf20Sopenharmony_cistruct pmc_reg_map { 268c2ecf20Sopenharmony_ci const struct pmc_bit_map *d3_sts_0; 278c2ecf20Sopenharmony_ci const struct pmc_bit_map *d3_sts_1; 288c2ecf20Sopenharmony_ci const struct pmc_bit_map *func_dis; 298c2ecf20Sopenharmony_ci const struct pmc_bit_map *func_dis_2; 308c2ecf20Sopenharmony_ci const struct pmc_bit_map *pss; 318c2ecf20Sopenharmony_ci}; 328c2ecf20Sopenharmony_ci 338c2ecf20Sopenharmony_cistruct pmc_data { 348c2ecf20Sopenharmony_ci const struct pmc_reg_map *map; 358c2ecf20Sopenharmony_ci const struct pmc_clk *clks; 368c2ecf20Sopenharmony_ci}; 378c2ecf20Sopenharmony_ci 388c2ecf20Sopenharmony_cistruct pmc_dev { 398c2ecf20Sopenharmony_ci u32 base_addr; 408c2ecf20Sopenharmony_ci void __iomem *regmap; 418c2ecf20Sopenharmony_ci const struct pmc_reg_map *map; 428c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 438c2ecf20Sopenharmony_ci struct dentry *dbgfs_dir; 448c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 458c2ecf20Sopenharmony_ci bool init; 468c2ecf20Sopenharmony_ci}; 478c2ecf20Sopenharmony_ci 488c2ecf20Sopenharmony_cistatic struct pmc_dev pmc_device; 498c2ecf20Sopenharmony_cistatic u32 acpi_base_addr; 508c2ecf20Sopenharmony_ci 518c2ecf20Sopenharmony_cistatic const struct pmc_clk byt_clks[] = { 528c2ecf20Sopenharmony_ci { 538c2ecf20Sopenharmony_ci .name = "xtal", 548c2ecf20Sopenharmony_ci .freq = 25000000, 558c2ecf20Sopenharmony_ci .parent_name = NULL, 568c2ecf20Sopenharmony_ci }, 578c2ecf20Sopenharmony_ci { 588c2ecf20Sopenharmony_ci .name = "pll", 598c2ecf20Sopenharmony_ci .freq = 19200000, 608c2ecf20Sopenharmony_ci .parent_name = "xtal", 618c2ecf20Sopenharmony_ci }, 628c2ecf20Sopenharmony_ci {}, 638c2ecf20Sopenharmony_ci}; 648c2ecf20Sopenharmony_ci 658c2ecf20Sopenharmony_cistatic const struct pmc_clk cht_clks[] = { 668c2ecf20Sopenharmony_ci { 678c2ecf20Sopenharmony_ci .name = "xtal", 688c2ecf20Sopenharmony_ci .freq = 19200000, 698c2ecf20Sopenharmony_ci .parent_name = NULL, 708c2ecf20Sopenharmony_ci }, 718c2ecf20Sopenharmony_ci {}, 728c2ecf20Sopenharmony_ci}; 738c2ecf20Sopenharmony_ci 748c2ecf20Sopenharmony_cistatic const struct pmc_bit_map d3_sts_0_map[] = { 758c2ecf20Sopenharmony_ci {"LPSS1_F0_DMA", BIT_LPSS1_F0_DMA}, 768c2ecf20Sopenharmony_ci {"LPSS1_F1_PWM1", BIT_LPSS1_F1_PWM1}, 778c2ecf20Sopenharmony_ci {"LPSS1_F2_PWM2", BIT_LPSS1_F2_PWM2}, 788c2ecf20Sopenharmony_ci {"LPSS1_F3_HSUART1", BIT_LPSS1_F3_HSUART1}, 798c2ecf20Sopenharmony_ci {"LPSS1_F4_HSUART2", BIT_LPSS1_F4_HSUART2}, 808c2ecf20Sopenharmony_ci {"LPSS1_F5_SPI", BIT_LPSS1_F5_SPI}, 818c2ecf20Sopenharmony_ci {"LPSS1_F6_Reserved", BIT_LPSS1_F6_XXX}, 828c2ecf20Sopenharmony_ci {"LPSS1_F7_Reserved", BIT_LPSS1_F7_XXX}, 838c2ecf20Sopenharmony_ci {"SCC_EMMC", BIT_SCC_EMMC}, 848c2ecf20Sopenharmony_ci {"SCC_SDIO", BIT_SCC_SDIO}, 858c2ecf20Sopenharmony_ci {"SCC_SDCARD", BIT_SCC_SDCARD}, 868c2ecf20Sopenharmony_ci {"SCC_MIPI", BIT_SCC_MIPI}, 878c2ecf20Sopenharmony_ci {"HDA", BIT_HDA}, 888c2ecf20Sopenharmony_ci {"LPE", BIT_LPE}, 898c2ecf20Sopenharmony_ci {"OTG", BIT_OTG}, 908c2ecf20Sopenharmony_ci {"USH", BIT_USH}, 918c2ecf20Sopenharmony_ci {"GBE", BIT_GBE}, 928c2ecf20Sopenharmony_ci {"SATA", BIT_SATA}, 938c2ecf20Sopenharmony_ci {"USB_EHCI", BIT_USB_EHCI}, 948c2ecf20Sopenharmony_ci {"SEC", BIT_SEC}, 958c2ecf20Sopenharmony_ci {"PCIE_PORT0", BIT_PCIE_PORT0}, 968c2ecf20Sopenharmony_ci {"PCIE_PORT1", BIT_PCIE_PORT1}, 978c2ecf20Sopenharmony_ci {"PCIE_PORT2", BIT_PCIE_PORT2}, 988c2ecf20Sopenharmony_ci {"PCIE_PORT3", BIT_PCIE_PORT3}, 998c2ecf20Sopenharmony_ci {"LPSS2_F0_DMA", BIT_LPSS2_F0_DMA}, 1008c2ecf20Sopenharmony_ci {"LPSS2_F1_I2C1", BIT_LPSS2_F1_I2C1}, 1018c2ecf20Sopenharmony_ci {"LPSS2_F2_I2C2", BIT_LPSS2_F2_I2C2}, 1028c2ecf20Sopenharmony_ci {"LPSS2_F3_I2C3", BIT_LPSS2_F3_I2C3}, 1038c2ecf20Sopenharmony_ci {"LPSS2_F3_I2C4", BIT_LPSS2_F4_I2C4}, 1048c2ecf20Sopenharmony_ci {"LPSS2_F5_I2C5", BIT_LPSS2_F5_I2C5}, 1058c2ecf20Sopenharmony_ci {"LPSS2_F6_I2C6", BIT_LPSS2_F6_I2C6}, 1068c2ecf20Sopenharmony_ci {"LPSS2_F7_I2C7", BIT_LPSS2_F7_I2C7}, 1078c2ecf20Sopenharmony_ci {}, 1088c2ecf20Sopenharmony_ci}; 1098c2ecf20Sopenharmony_ci 1108c2ecf20Sopenharmony_cistatic struct pmc_bit_map byt_d3_sts_1_map[] = { 1118c2ecf20Sopenharmony_ci {"SMB", BIT_SMB}, 1128c2ecf20Sopenharmony_ci {"OTG_SS_PHY", BIT_OTG_SS_PHY}, 1138c2ecf20Sopenharmony_ci {"USH_SS_PHY", BIT_USH_SS_PHY}, 1148c2ecf20Sopenharmony_ci {"DFX", BIT_DFX}, 1158c2ecf20Sopenharmony_ci {}, 1168c2ecf20Sopenharmony_ci}; 1178c2ecf20Sopenharmony_ci 1188c2ecf20Sopenharmony_cistatic struct pmc_bit_map cht_d3_sts_1_map[] = { 1198c2ecf20Sopenharmony_ci {"SMB", BIT_SMB}, 1208c2ecf20Sopenharmony_ci {"GMM", BIT_STS_GMM}, 1218c2ecf20Sopenharmony_ci {"ISH", BIT_STS_ISH}, 1228c2ecf20Sopenharmony_ci {}, 1238c2ecf20Sopenharmony_ci}; 1248c2ecf20Sopenharmony_ci 1258c2ecf20Sopenharmony_cistatic struct pmc_bit_map cht_func_dis_2_map[] = { 1268c2ecf20Sopenharmony_ci {"SMB", BIT_SMB}, 1278c2ecf20Sopenharmony_ci {"GMM", BIT_FD_GMM}, 1288c2ecf20Sopenharmony_ci {"ISH", BIT_FD_ISH}, 1298c2ecf20Sopenharmony_ci {}, 1308c2ecf20Sopenharmony_ci}; 1318c2ecf20Sopenharmony_ci 1328c2ecf20Sopenharmony_cistatic const struct pmc_bit_map byt_pss_map[] = { 1338c2ecf20Sopenharmony_ci {"GBE", PMC_PSS_BIT_GBE}, 1348c2ecf20Sopenharmony_ci {"SATA", PMC_PSS_BIT_SATA}, 1358c2ecf20Sopenharmony_ci {"HDA", PMC_PSS_BIT_HDA}, 1368c2ecf20Sopenharmony_ci {"SEC", PMC_PSS_BIT_SEC}, 1378c2ecf20Sopenharmony_ci {"PCIE", PMC_PSS_BIT_PCIE}, 1388c2ecf20Sopenharmony_ci {"LPSS", PMC_PSS_BIT_LPSS}, 1398c2ecf20Sopenharmony_ci {"LPE", PMC_PSS_BIT_LPE}, 1408c2ecf20Sopenharmony_ci {"DFX", PMC_PSS_BIT_DFX}, 1418c2ecf20Sopenharmony_ci {"USH_CTRL", PMC_PSS_BIT_USH_CTRL}, 1428c2ecf20Sopenharmony_ci {"USH_SUS", PMC_PSS_BIT_USH_SUS}, 1438c2ecf20Sopenharmony_ci {"USH_VCCS", PMC_PSS_BIT_USH_VCCS}, 1448c2ecf20Sopenharmony_ci {"USH_VCCA", PMC_PSS_BIT_USH_VCCA}, 1458c2ecf20Sopenharmony_ci {"OTG_CTRL", PMC_PSS_BIT_OTG_CTRL}, 1468c2ecf20Sopenharmony_ci {"OTG_VCCS", PMC_PSS_BIT_OTG_VCCS}, 1478c2ecf20Sopenharmony_ci {"OTG_VCCA_CLK", PMC_PSS_BIT_OTG_VCCA_CLK}, 1488c2ecf20Sopenharmony_ci {"OTG_VCCA", PMC_PSS_BIT_OTG_VCCA}, 1498c2ecf20Sopenharmony_ci {"USB", PMC_PSS_BIT_USB}, 1508c2ecf20Sopenharmony_ci {"USB_SUS", PMC_PSS_BIT_USB_SUS}, 1518c2ecf20Sopenharmony_ci {}, 1528c2ecf20Sopenharmony_ci}; 1538c2ecf20Sopenharmony_ci 1548c2ecf20Sopenharmony_cistatic const struct pmc_bit_map cht_pss_map[] = { 1558c2ecf20Sopenharmony_ci {"SATA", PMC_PSS_BIT_SATA}, 1568c2ecf20Sopenharmony_ci {"HDA", PMC_PSS_BIT_HDA}, 1578c2ecf20Sopenharmony_ci {"SEC", PMC_PSS_BIT_SEC}, 1588c2ecf20Sopenharmony_ci {"PCIE", PMC_PSS_BIT_PCIE}, 1598c2ecf20Sopenharmony_ci {"LPSS", PMC_PSS_BIT_LPSS}, 1608c2ecf20Sopenharmony_ci {"LPE", PMC_PSS_BIT_LPE}, 1618c2ecf20Sopenharmony_ci {"UFS", PMC_PSS_BIT_CHT_UFS}, 1628c2ecf20Sopenharmony_ci {"UXD", PMC_PSS_BIT_CHT_UXD}, 1638c2ecf20Sopenharmony_ci {"UXD_FD", PMC_PSS_BIT_CHT_UXD_FD}, 1648c2ecf20Sopenharmony_ci {"UX_ENG", PMC_PSS_BIT_CHT_UX_ENG}, 1658c2ecf20Sopenharmony_ci {"USB_SUS", PMC_PSS_BIT_CHT_USB_SUS}, 1668c2ecf20Sopenharmony_ci {"GMM", PMC_PSS_BIT_CHT_GMM}, 1678c2ecf20Sopenharmony_ci {"ISH", PMC_PSS_BIT_CHT_ISH}, 1688c2ecf20Sopenharmony_ci {"DFX_MASTER", PMC_PSS_BIT_CHT_DFX_MASTER}, 1698c2ecf20Sopenharmony_ci {"DFX_CLUSTER1", PMC_PSS_BIT_CHT_DFX_CLUSTER1}, 1708c2ecf20Sopenharmony_ci {"DFX_CLUSTER2", PMC_PSS_BIT_CHT_DFX_CLUSTER2}, 1718c2ecf20Sopenharmony_ci {"DFX_CLUSTER3", PMC_PSS_BIT_CHT_DFX_CLUSTER3}, 1728c2ecf20Sopenharmony_ci {"DFX_CLUSTER4", PMC_PSS_BIT_CHT_DFX_CLUSTER4}, 1738c2ecf20Sopenharmony_ci {"DFX_CLUSTER5", PMC_PSS_BIT_CHT_DFX_CLUSTER5}, 1748c2ecf20Sopenharmony_ci {}, 1758c2ecf20Sopenharmony_ci}; 1768c2ecf20Sopenharmony_ci 1778c2ecf20Sopenharmony_cistatic const struct pmc_reg_map byt_reg_map = { 1788c2ecf20Sopenharmony_ci .d3_sts_0 = d3_sts_0_map, 1798c2ecf20Sopenharmony_ci .d3_sts_1 = byt_d3_sts_1_map, 1808c2ecf20Sopenharmony_ci .func_dis = d3_sts_0_map, 1818c2ecf20Sopenharmony_ci .func_dis_2 = byt_d3_sts_1_map, 1828c2ecf20Sopenharmony_ci .pss = byt_pss_map, 1838c2ecf20Sopenharmony_ci}; 1848c2ecf20Sopenharmony_ci 1858c2ecf20Sopenharmony_cistatic const struct pmc_reg_map cht_reg_map = { 1868c2ecf20Sopenharmony_ci .d3_sts_0 = d3_sts_0_map, 1878c2ecf20Sopenharmony_ci .d3_sts_1 = cht_d3_sts_1_map, 1888c2ecf20Sopenharmony_ci .func_dis = d3_sts_0_map, 1898c2ecf20Sopenharmony_ci .func_dis_2 = cht_func_dis_2_map, 1908c2ecf20Sopenharmony_ci .pss = cht_pss_map, 1918c2ecf20Sopenharmony_ci}; 1928c2ecf20Sopenharmony_ci 1938c2ecf20Sopenharmony_cistatic const struct pmc_data byt_data = { 1948c2ecf20Sopenharmony_ci .map = &byt_reg_map, 1958c2ecf20Sopenharmony_ci .clks = byt_clks, 1968c2ecf20Sopenharmony_ci}; 1978c2ecf20Sopenharmony_ci 1988c2ecf20Sopenharmony_cistatic const struct pmc_data cht_data = { 1998c2ecf20Sopenharmony_ci .map = &cht_reg_map, 2008c2ecf20Sopenharmony_ci .clks = cht_clks, 2018c2ecf20Sopenharmony_ci}; 2028c2ecf20Sopenharmony_ci 2038c2ecf20Sopenharmony_cistatic inline u32 pmc_reg_read(struct pmc_dev *pmc, int reg_offset) 2048c2ecf20Sopenharmony_ci{ 2058c2ecf20Sopenharmony_ci return readl(pmc->regmap + reg_offset); 2068c2ecf20Sopenharmony_ci} 2078c2ecf20Sopenharmony_ci 2088c2ecf20Sopenharmony_cistatic inline void pmc_reg_write(struct pmc_dev *pmc, int reg_offset, u32 val) 2098c2ecf20Sopenharmony_ci{ 2108c2ecf20Sopenharmony_ci writel(val, pmc->regmap + reg_offset); 2118c2ecf20Sopenharmony_ci} 2128c2ecf20Sopenharmony_ci 2138c2ecf20Sopenharmony_ciint pmc_atom_read(int offset, u32 *value) 2148c2ecf20Sopenharmony_ci{ 2158c2ecf20Sopenharmony_ci struct pmc_dev *pmc = &pmc_device; 2168c2ecf20Sopenharmony_ci 2178c2ecf20Sopenharmony_ci if (!pmc->init) 2188c2ecf20Sopenharmony_ci return -ENODEV; 2198c2ecf20Sopenharmony_ci 2208c2ecf20Sopenharmony_ci *value = pmc_reg_read(pmc, offset); 2218c2ecf20Sopenharmony_ci return 0; 2228c2ecf20Sopenharmony_ci} 2238c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pmc_atom_read); 2248c2ecf20Sopenharmony_ci 2258c2ecf20Sopenharmony_ciint pmc_atom_write(int offset, u32 value) 2268c2ecf20Sopenharmony_ci{ 2278c2ecf20Sopenharmony_ci struct pmc_dev *pmc = &pmc_device; 2288c2ecf20Sopenharmony_ci 2298c2ecf20Sopenharmony_ci if (!pmc->init) 2308c2ecf20Sopenharmony_ci return -ENODEV; 2318c2ecf20Sopenharmony_ci 2328c2ecf20Sopenharmony_ci pmc_reg_write(pmc, offset, value); 2338c2ecf20Sopenharmony_ci return 0; 2348c2ecf20Sopenharmony_ci} 2358c2ecf20Sopenharmony_ciEXPORT_SYMBOL_GPL(pmc_atom_write); 2368c2ecf20Sopenharmony_ci 2378c2ecf20Sopenharmony_cistatic void pmc_power_off(void) 2388c2ecf20Sopenharmony_ci{ 2398c2ecf20Sopenharmony_ci u16 pm1_cnt_port; 2408c2ecf20Sopenharmony_ci u32 pm1_cnt_value; 2418c2ecf20Sopenharmony_ci 2428c2ecf20Sopenharmony_ci pr_info("Preparing to enter system sleep state S5\n"); 2438c2ecf20Sopenharmony_ci 2448c2ecf20Sopenharmony_ci pm1_cnt_port = acpi_base_addr + PM1_CNT; 2458c2ecf20Sopenharmony_ci 2468c2ecf20Sopenharmony_ci pm1_cnt_value = inl(pm1_cnt_port); 2478c2ecf20Sopenharmony_ci pm1_cnt_value &= ~SLEEP_TYPE_MASK; 2488c2ecf20Sopenharmony_ci pm1_cnt_value |= SLEEP_TYPE_S5; 2498c2ecf20Sopenharmony_ci pm1_cnt_value |= SLEEP_ENABLE; 2508c2ecf20Sopenharmony_ci 2518c2ecf20Sopenharmony_ci outl(pm1_cnt_value, pm1_cnt_port); 2528c2ecf20Sopenharmony_ci} 2538c2ecf20Sopenharmony_ci 2548c2ecf20Sopenharmony_cistatic void pmc_hw_reg_setup(struct pmc_dev *pmc) 2558c2ecf20Sopenharmony_ci{ 2568c2ecf20Sopenharmony_ci /* 2578c2ecf20Sopenharmony_ci * Disable PMC S0IX_WAKE_EN events coming from: 2588c2ecf20Sopenharmony_ci * - LPC clock run 2598c2ecf20Sopenharmony_ci * - GPIO_SUS ored dedicated IRQs 2608c2ecf20Sopenharmony_ci * - GPIO_SCORE ored dedicated IRQs 2618c2ecf20Sopenharmony_ci * - GPIO_SUS shared IRQ 2628c2ecf20Sopenharmony_ci * - GPIO_SCORE shared IRQ 2638c2ecf20Sopenharmony_ci */ 2648c2ecf20Sopenharmony_ci pmc_reg_write(pmc, PMC_S0IX_WAKE_EN, (u32)PMC_WAKE_EN_SETTING); 2658c2ecf20Sopenharmony_ci} 2668c2ecf20Sopenharmony_ci 2678c2ecf20Sopenharmony_ci#ifdef CONFIG_DEBUG_FS 2688c2ecf20Sopenharmony_cistatic void pmc_dev_state_print(struct seq_file *s, int reg_index, 2698c2ecf20Sopenharmony_ci u32 sts, const struct pmc_bit_map *sts_map, 2708c2ecf20Sopenharmony_ci u32 fd, const struct pmc_bit_map *fd_map) 2718c2ecf20Sopenharmony_ci{ 2728c2ecf20Sopenharmony_ci int offset = PMC_REG_BIT_WIDTH * reg_index; 2738c2ecf20Sopenharmony_ci int index; 2748c2ecf20Sopenharmony_ci 2758c2ecf20Sopenharmony_ci for (index = 0; sts_map[index].name; index++) { 2768c2ecf20Sopenharmony_ci seq_printf(s, "Dev: %-2d - %-32s\tState: %s [%s]\n", 2778c2ecf20Sopenharmony_ci offset + index, sts_map[index].name, 2788c2ecf20Sopenharmony_ci fd_map[index].bit_mask & fd ? "Disabled" : "Enabled ", 2798c2ecf20Sopenharmony_ci sts_map[index].bit_mask & sts ? "D3" : "D0"); 2808c2ecf20Sopenharmony_ci } 2818c2ecf20Sopenharmony_ci} 2828c2ecf20Sopenharmony_ci 2838c2ecf20Sopenharmony_cistatic int pmc_dev_state_show(struct seq_file *s, void *unused) 2848c2ecf20Sopenharmony_ci{ 2858c2ecf20Sopenharmony_ci struct pmc_dev *pmc = s->private; 2868c2ecf20Sopenharmony_ci const struct pmc_reg_map *m = pmc->map; 2878c2ecf20Sopenharmony_ci u32 func_dis, func_dis_2; 2888c2ecf20Sopenharmony_ci u32 d3_sts_0, d3_sts_1; 2898c2ecf20Sopenharmony_ci 2908c2ecf20Sopenharmony_ci func_dis = pmc_reg_read(pmc, PMC_FUNC_DIS); 2918c2ecf20Sopenharmony_ci func_dis_2 = pmc_reg_read(pmc, PMC_FUNC_DIS_2); 2928c2ecf20Sopenharmony_ci d3_sts_0 = pmc_reg_read(pmc, PMC_D3_STS_0); 2938c2ecf20Sopenharmony_ci d3_sts_1 = pmc_reg_read(pmc, PMC_D3_STS_1); 2948c2ecf20Sopenharmony_ci 2958c2ecf20Sopenharmony_ci /* Low part */ 2968c2ecf20Sopenharmony_ci pmc_dev_state_print(s, 0, d3_sts_0, m->d3_sts_0, func_dis, m->func_dis); 2978c2ecf20Sopenharmony_ci 2988c2ecf20Sopenharmony_ci /* High part */ 2998c2ecf20Sopenharmony_ci pmc_dev_state_print(s, 1, d3_sts_1, m->d3_sts_1, func_dis_2, m->func_dis_2); 3008c2ecf20Sopenharmony_ci 3018c2ecf20Sopenharmony_ci return 0; 3028c2ecf20Sopenharmony_ci} 3038c2ecf20Sopenharmony_ci 3048c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pmc_dev_state); 3058c2ecf20Sopenharmony_ci 3068c2ecf20Sopenharmony_cistatic int pmc_pss_state_show(struct seq_file *s, void *unused) 3078c2ecf20Sopenharmony_ci{ 3088c2ecf20Sopenharmony_ci struct pmc_dev *pmc = s->private; 3098c2ecf20Sopenharmony_ci const struct pmc_bit_map *map = pmc->map->pss; 3108c2ecf20Sopenharmony_ci u32 pss = pmc_reg_read(pmc, PMC_PSS); 3118c2ecf20Sopenharmony_ci int index; 3128c2ecf20Sopenharmony_ci 3138c2ecf20Sopenharmony_ci for (index = 0; map[index].name; index++) { 3148c2ecf20Sopenharmony_ci seq_printf(s, "Island: %-2d - %-32s\tState: %s\n", 3158c2ecf20Sopenharmony_ci index, map[index].name, 3168c2ecf20Sopenharmony_ci map[index].bit_mask & pss ? "Off" : "On"); 3178c2ecf20Sopenharmony_ci } 3188c2ecf20Sopenharmony_ci return 0; 3198c2ecf20Sopenharmony_ci} 3208c2ecf20Sopenharmony_ci 3218c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pmc_pss_state); 3228c2ecf20Sopenharmony_ci 3238c2ecf20Sopenharmony_cistatic int pmc_sleep_tmr_show(struct seq_file *s, void *unused) 3248c2ecf20Sopenharmony_ci{ 3258c2ecf20Sopenharmony_ci struct pmc_dev *pmc = s->private; 3268c2ecf20Sopenharmony_ci u64 s0ir_tmr, s0i1_tmr, s0i2_tmr, s0i3_tmr, s0_tmr; 3278c2ecf20Sopenharmony_ci 3288c2ecf20Sopenharmony_ci s0ir_tmr = (u64)pmc_reg_read(pmc, PMC_S0IR_TMR) << PMC_TMR_SHIFT; 3298c2ecf20Sopenharmony_ci s0i1_tmr = (u64)pmc_reg_read(pmc, PMC_S0I1_TMR) << PMC_TMR_SHIFT; 3308c2ecf20Sopenharmony_ci s0i2_tmr = (u64)pmc_reg_read(pmc, PMC_S0I2_TMR) << PMC_TMR_SHIFT; 3318c2ecf20Sopenharmony_ci s0i3_tmr = (u64)pmc_reg_read(pmc, PMC_S0I3_TMR) << PMC_TMR_SHIFT; 3328c2ecf20Sopenharmony_ci s0_tmr = (u64)pmc_reg_read(pmc, PMC_S0_TMR) << PMC_TMR_SHIFT; 3338c2ecf20Sopenharmony_ci 3348c2ecf20Sopenharmony_ci seq_printf(s, "S0IR Residency:\t%lldus\n", s0ir_tmr); 3358c2ecf20Sopenharmony_ci seq_printf(s, "S0I1 Residency:\t%lldus\n", s0i1_tmr); 3368c2ecf20Sopenharmony_ci seq_printf(s, "S0I2 Residency:\t%lldus\n", s0i2_tmr); 3378c2ecf20Sopenharmony_ci seq_printf(s, "S0I3 Residency:\t%lldus\n", s0i3_tmr); 3388c2ecf20Sopenharmony_ci seq_printf(s, "S0 Residency:\t%lldus\n", s0_tmr); 3398c2ecf20Sopenharmony_ci return 0; 3408c2ecf20Sopenharmony_ci} 3418c2ecf20Sopenharmony_ci 3428c2ecf20Sopenharmony_ciDEFINE_SHOW_ATTRIBUTE(pmc_sleep_tmr); 3438c2ecf20Sopenharmony_ci 3448c2ecf20Sopenharmony_cistatic void pmc_dbgfs_register(struct pmc_dev *pmc) 3458c2ecf20Sopenharmony_ci{ 3468c2ecf20Sopenharmony_ci struct dentry *dir; 3478c2ecf20Sopenharmony_ci 3488c2ecf20Sopenharmony_ci dir = debugfs_create_dir("pmc_atom", NULL); 3498c2ecf20Sopenharmony_ci 3508c2ecf20Sopenharmony_ci pmc->dbgfs_dir = dir; 3518c2ecf20Sopenharmony_ci 3528c2ecf20Sopenharmony_ci debugfs_create_file("dev_state", S_IFREG | S_IRUGO, dir, pmc, 3538c2ecf20Sopenharmony_ci &pmc_dev_state_fops); 3548c2ecf20Sopenharmony_ci debugfs_create_file("pss_state", S_IFREG | S_IRUGO, dir, pmc, 3558c2ecf20Sopenharmony_ci &pmc_pss_state_fops); 3568c2ecf20Sopenharmony_ci debugfs_create_file("sleep_state", S_IFREG | S_IRUGO, dir, pmc, 3578c2ecf20Sopenharmony_ci &pmc_sleep_tmr_fops); 3588c2ecf20Sopenharmony_ci} 3598c2ecf20Sopenharmony_ci#else 3608c2ecf20Sopenharmony_cistatic void pmc_dbgfs_register(struct pmc_dev *pmc) 3618c2ecf20Sopenharmony_ci{ 3628c2ecf20Sopenharmony_ci} 3638c2ecf20Sopenharmony_ci#endif /* CONFIG_DEBUG_FS */ 3648c2ecf20Sopenharmony_ci 3658c2ecf20Sopenharmony_ci/* 3668c2ecf20Sopenharmony_ci * Some systems need one or more of their pmc_plt_clks to be 3678c2ecf20Sopenharmony_ci * marked as critical. 3688c2ecf20Sopenharmony_ci */ 3698c2ecf20Sopenharmony_cistatic const struct dmi_system_id critclk_systems[] = { 3708c2ecf20Sopenharmony_ci { 3718c2ecf20Sopenharmony_ci /* pmc_plt_clk0 is used for an external HSIC USB HUB */ 3728c2ecf20Sopenharmony_ci .ident = "MPL CEC1x", 3738c2ecf20Sopenharmony_ci .matches = { 3748c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "MPL AG"), 3758c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "CEC10 Family"), 3768c2ecf20Sopenharmony_ci }, 3778c2ecf20Sopenharmony_ci }, 3788c2ecf20Sopenharmony_ci { 3798c2ecf20Sopenharmony_ci /* pmc_plt_clk0 - 3 are used for the 4 ethernet controllers */ 3808c2ecf20Sopenharmony_ci .ident = "Lex 3I380D", 3818c2ecf20Sopenharmony_ci .matches = { 3828c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"), 3838c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "3I380D"), 3848c2ecf20Sopenharmony_ci }, 3858c2ecf20Sopenharmony_ci }, 3868c2ecf20Sopenharmony_ci { 3878c2ecf20Sopenharmony_ci /* pmc_plt_clk* - are used for ethernet controllers */ 3888c2ecf20Sopenharmony_ci .ident = "Lex 2I385SW", 3898c2ecf20Sopenharmony_ci .matches = { 3908c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Lex BayTrail"), 3918c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_NAME, "2I385SW"), 3928c2ecf20Sopenharmony_ci }, 3938c2ecf20Sopenharmony_ci }, 3948c2ecf20Sopenharmony_ci { 3958c2ecf20Sopenharmony_ci /* pmc_plt_clk* - are used for ethernet controllers */ 3968c2ecf20Sopenharmony_ci .ident = "Beckhoff Baytrail", 3978c2ecf20Sopenharmony_ci .matches = { 3988c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "Beckhoff Automation"), 3998c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_FAMILY, "CBxx63"), 4008c2ecf20Sopenharmony_ci }, 4018c2ecf20Sopenharmony_ci }, 4028c2ecf20Sopenharmony_ci { 4038c2ecf20Sopenharmony_ci .ident = "SIMATIC IPC227E", 4048c2ecf20Sopenharmony_ci .matches = { 4058c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"), 4068c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_VERSION, "6ES7647-8B"), 4078c2ecf20Sopenharmony_ci }, 4088c2ecf20Sopenharmony_ci }, 4098c2ecf20Sopenharmony_ci { 4108c2ecf20Sopenharmony_ci .ident = "SIMATIC IPC277E", 4118c2ecf20Sopenharmony_ci .matches = { 4128c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"), 4138c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_VERSION, "6AV7882-0"), 4148c2ecf20Sopenharmony_ci }, 4158c2ecf20Sopenharmony_ci }, 4168c2ecf20Sopenharmony_ci { 4178c2ecf20Sopenharmony_ci .ident = "CONNECT X300", 4188c2ecf20Sopenharmony_ci .matches = { 4198c2ecf20Sopenharmony_ci DMI_MATCH(DMI_SYS_VENDOR, "SIEMENS AG"), 4208c2ecf20Sopenharmony_ci DMI_MATCH(DMI_PRODUCT_VERSION, "A5E45074588"), 4218c2ecf20Sopenharmony_ci }, 4228c2ecf20Sopenharmony_ci }, 4238c2ecf20Sopenharmony_ci 4248c2ecf20Sopenharmony_ci { /*sentinel*/ } 4258c2ecf20Sopenharmony_ci}; 4268c2ecf20Sopenharmony_ci 4278c2ecf20Sopenharmony_cistatic int pmc_setup_clks(struct pci_dev *pdev, void __iomem *pmc_regmap, 4288c2ecf20Sopenharmony_ci const struct pmc_data *pmc_data) 4298c2ecf20Sopenharmony_ci{ 4308c2ecf20Sopenharmony_ci struct platform_device *clkdev; 4318c2ecf20Sopenharmony_ci struct pmc_clk_data *clk_data; 4328c2ecf20Sopenharmony_ci const struct dmi_system_id *d = dmi_first_match(critclk_systems); 4338c2ecf20Sopenharmony_ci 4348c2ecf20Sopenharmony_ci clk_data = kzalloc(sizeof(*clk_data), GFP_KERNEL); 4358c2ecf20Sopenharmony_ci if (!clk_data) 4368c2ecf20Sopenharmony_ci return -ENOMEM; 4378c2ecf20Sopenharmony_ci 4388c2ecf20Sopenharmony_ci clk_data->base = pmc_regmap; /* offset is added by client */ 4398c2ecf20Sopenharmony_ci clk_data->clks = pmc_data->clks; 4408c2ecf20Sopenharmony_ci if (d) { 4418c2ecf20Sopenharmony_ci clk_data->critical = true; 4428c2ecf20Sopenharmony_ci pr_info("%s critclks quirk enabled\n", d->ident); 4438c2ecf20Sopenharmony_ci } 4448c2ecf20Sopenharmony_ci 4458c2ecf20Sopenharmony_ci clkdev = platform_device_register_data(&pdev->dev, "clk-pmc-atom", 4468c2ecf20Sopenharmony_ci PLATFORM_DEVID_NONE, 4478c2ecf20Sopenharmony_ci clk_data, sizeof(*clk_data)); 4488c2ecf20Sopenharmony_ci if (IS_ERR(clkdev)) { 4498c2ecf20Sopenharmony_ci kfree(clk_data); 4508c2ecf20Sopenharmony_ci return PTR_ERR(clkdev); 4518c2ecf20Sopenharmony_ci } 4528c2ecf20Sopenharmony_ci 4538c2ecf20Sopenharmony_ci kfree(clk_data); 4548c2ecf20Sopenharmony_ci 4558c2ecf20Sopenharmony_ci return 0; 4568c2ecf20Sopenharmony_ci} 4578c2ecf20Sopenharmony_ci 4588c2ecf20Sopenharmony_cistatic int pmc_setup_dev(struct pci_dev *pdev, const struct pci_device_id *ent) 4598c2ecf20Sopenharmony_ci{ 4608c2ecf20Sopenharmony_ci struct pmc_dev *pmc = &pmc_device; 4618c2ecf20Sopenharmony_ci const struct pmc_data *data = (struct pmc_data *)ent->driver_data; 4628c2ecf20Sopenharmony_ci const struct pmc_reg_map *map = data->map; 4638c2ecf20Sopenharmony_ci int ret; 4648c2ecf20Sopenharmony_ci 4658c2ecf20Sopenharmony_ci /* Obtain ACPI base address */ 4668c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, ACPI_BASE_ADDR_OFFSET, &acpi_base_addr); 4678c2ecf20Sopenharmony_ci acpi_base_addr &= ACPI_BASE_ADDR_MASK; 4688c2ecf20Sopenharmony_ci 4698c2ecf20Sopenharmony_ci /* Install power off function */ 4708c2ecf20Sopenharmony_ci if (acpi_base_addr != 0 && pm_power_off == NULL) 4718c2ecf20Sopenharmony_ci pm_power_off = pmc_power_off; 4728c2ecf20Sopenharmony_ci 4738c2ecf20Sopenharmony_ci pci_read_config_dword(pdev, PMC_BASE_ADDR_OFFSET, &pmc->base_addr); 4748c2ecf20Sopenharmony_ci pmc->base_addr &= PMC_BASE_ADDR_MASK; 4758c2ecf20Sopenharmony_ci 4768c2ecf20Sopenharmony_ci pmc->regmap = ioremap(pmc->base_addr, PMC_MMIO_REG_LEN); 4778c2ecf20Sopenharmony_ci if (!pmc->regmap) { 4788c2ecf20Sopenharmony_ci dev_err(&pdev->dev, "error: ioremap failed\n"); 4798c2ecf20Sopenharmony_ci return -ENOMEM; 4808c2ecf20Sopenharmony_ci } 4818c2ecf20Sopenharmony_ci 4828c2ecf20Sopenharmony_ci pmc->map = map; 4838c2ecf20Sopenharmony_ci 4848c2ecf20Sopenharmony_ci /* PMC hardware registers setup */ 4858c2ecf20Sopenharmony_ci pmc_hw_reg_setup(pmc); 4868c2ecf20Sopenharmony_ci 4878c2ecf20Sopenharmony_ci pmc_dbgfs_register(pmc); 4888c2ecf20Sopenharmony_ci 4898c2ecf20Sopenharmony_ci /* Register platform clocks - PMC_PLT_CLK [0..5] */ 4908c2ecf20Sopenharmony_ci ret = pmc_setup_clks(pdev, pmc->regmap, data); 4918c2ecf20Sopenharmony_ci if (ret) 4928c2ecf20Sopenharmony_ci dev_warn(&pdev->dev, "platform clocks register failed: %d\n", 4938c2ecf20Sopenharmony_ci ret); 4948c2ecf20Sopenharmony_ci 4958c2ecf20Sopenharmony_ci pmc->init = true; 4968c2ecf20Sopenharmony_ci return ret; 4978c2ecf20Sopenharmony_ci} 4988c2ecf20Sopenharmony_ci 4998c2ecf20Sopenharmony_ci/* 5008c2ecf20Sopenharmony_ci * Data for PCI driver interface 5018c2ecf20Sopenharmony_ci * 5028c2ecf20Sopenharmony_ci * used by pci_match_id() call below. 5038c2ecf20Sopenharmony_ci */ 5048c2ecf20Sopenharmony_cistatic const struct pci_device_id pmc_pci_ids[] = { 5058c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_VLV_PMC), (kernel_ulong_t)&byt_data }, 5068c2ecf20Sopenharmony_ci { PCI_VDEVICE(INTEL, PCI_DEVICE_ID_CHT_PMC), (kernel_ulong_t)&cht_data }, 5078c2ecf20Sopenharmony_ci { 0, }, 5088c2ecf20Sopenharmony_ci}; 5098c2ecf20Sopenharmony_ci 5108c2ecf20Sopenharmony_cistatic int __init pmc_atom_init(void) 5118c2ecf20Sopenharmony_ci{ 5128c2ecf20Sopenharmony_ci struct pci_dev *pdev = NULL; 5138c2ecf20Sopenharmony_ci const struct pci_device_id *ent; 5148c2ecf20Sopenharmony_ci 5158c2ecf20Sopenharmony_ci /* We look for our device - PCU PMC 5168c2ecf20Sopenharmony_ci * we assume that there is max. one device. 5178c2ecf20Sopenharmony_ci * 5188c2ecf20Sopenharmony_ci * We can't use plain pci_driver mechanism, 5198c2ecf20Sopenharmony_ci * as the device is really a multiple function device, 5208c2ecf20Sopenharmony_ci * main driver that binds to the pci_device is lpc_ich 5218c2ecf20Sopenharmony_ci * and have to find & bind to the device this way. 5228c2ecf20Sopenharmony_ci */ 5238c2ecf20Sopenharmony_ci for_each_pci_dev(pdev) { 5248c2ecf20Sopenharmony_ci ent = pci_match_id(pmc_pci_ids, pdev); 5258c2ecf20Sopenharmony_ci if (ent) 5268c2ecf20Sopenharmony_ci return pmc_setup_dev(pdev, ent); 5278c2ecf20Sopenharmony_ci } 5288c2ecf20Sopenharmony_ci /* Device not found. */ 5298c2ecf20Sopenharmony_ci return -ENODEV; 5308c2ecf20Sopenharmony_ci} 5318c2ecf20Sopenharmony_ci 5328c2ecf20Sopenharmony_cidevice_initcall(pmc_atom_init); 5338c2ecf20Sopenharmony_ci 5348c2ecf20Sopenharmony_ci/* 5358c2ecf20Sopenharmony_ciMODULE_AUTHOR("Aubrey Li <aubrey.li@linux.intel.com>"); 5368c2ecf20Sopenharmony_ciMODULE_DESCRIPTION("Intel Atom SOC Power Management Controller Interface"); 5378c2ecf20Sopenharmony_ciMODULE_LICENSE("GPL v2"); 5388c2ecf20Sopenharmony_ci*/ 539