Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

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