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)  * Copyright (C) 2016 Freescale Semiconductor, Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  * Copyright 2017-2018 NXP
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  *	Dong Aisheng <aisheng.dong@nxp.com>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7)  * Implementation of the SCU based Power Domains
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9)  * NOTE: a better implementation suggested by Ulf Hansson is using a
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10)  * single global power domain and implement the ->attach|detach_dev()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11)  * callback for the genpd and use the regular of_genpd_add_provider_simple().
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12)  * From within the ->attach_dev(), we could get the OF node for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13)  * the device that is being attached and then parse the power-domain
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14)  * cell containing the "resource id" and store that in the per device
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15)  * struct generic_pm_domain_data (we have void pointer there for
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16)  * storing these kind of things).
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18)  * Additionally, we need to implement the ->stop() and ->start()
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19)  * callbacks of genpd, which is where you "power on/off" devices,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  * rather than using the above ->power_on|off() callbacks.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  * However, there're two known issues:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  * 1. The ->attach_dev() of power domain infrastructure still does
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  *    not support multi domains case as the struct device *dev passed
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25)  *    in is a virtual PD device, it does not help for parsing the real
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  *    device resource id from device tree, so it's unware of which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  *    real sub power domain of device should be attached.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29)  *    The framework needs some proper extension to support multi power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30)  *    domain cases.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32)  * 2. It also breaks most of current drivers as the driver probe sequence
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33)  *    behavior changed if removing ->power_on|off() callback and use
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34)  *    ->start() and ->stop() instead. genpd_dev_pm_attach will only power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35)  *    up the domain and attach device, but will not call .start() which
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36)  *    relies on device runtime pm. That means the device power is still
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37)  *    not up before running driver probe function. For SCU enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38)  *    platforms, all device drivers accessing registers/clock without power
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39)  *    domain enabled will trigger a HW access error. That means we need fix
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40)  *    most drivers probe sequence with proper runtime pm.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42)  * In summary, we need fix above two issue before being able to switch to
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43)  * the "single global power domain" way.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47) #include <dt-bindings/firmware/imx/rsrc.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48) #include <linux/firmware/imx/sci.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49) #include <linux/firmware/imx/svc/rm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) #include <linux/io.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) #include <linux/module.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) #include <linux/of.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) #include <linux/of_address.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) #include <linux/of_platform.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) #include <linux/platform_device.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) #include <linux/pm.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) #include <linux/pm_domain.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) #include <linux/slab.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) /* SCU Power Mode Protocol definition */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) struct imx_sc_msg_req_set_resource_power_mode {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 	struct imx_sc_rpc_msg hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	u16 resource;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	u8 mode;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) } __packed __aligned(4);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) #define IMX_SCU_PD_NAME_SIZE 20
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) struct imx_sc_pm_domain {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 	struct generic_pm_domain pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 	char name[IMX_SCU_PD_NAME_SIZE];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	u32 rsrc;
^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) struct imx_sc_pd_range {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 	char *name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	u32 rsrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) 	u8 num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) 	/* add domain index */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80) 	bool postfix;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81) 	u8 start_from;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84) struct imx_sc_pd_soc {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) 	const struct imx_sc_pd_range *pd_ranges;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) 	u8 num_ranges;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) static const struct imx_sc_pd_range imx8qxp_scu_pd_ranges[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) 	/* LSIO SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	{ "pwm", IMX_SC_R_PWM_0, 8, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	{ "gpio", IMX_SC_R_GPIO_0, 8, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	{ "gpt", IMX_SC_R_GPT_0, 5, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 	{ "kpp", IMX_SC_R_KPP, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	{ "fspi", IMX_SC_R_FSPI_0, 2, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 	{ "mu_a", IMX_SC_R_MU_0A, 14, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 	{ "mu_b", IMX_SC_R_MU_5B, 9, true, 5 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	/* CONN SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 	{ "usb", IMX_SC_R_USB_0, 2, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 	{ "usb0phy", IMX_SC_R_USB_0_PHY, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	{ "usb2", IMX_SC_R_USB_2, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	{ "usb2phy", IMX_SC_R_USB_2_PHY, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 	{ "sdhc", IMX_SC_R_SDHC_0, 3, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 	{ "enet", IMX_SC_R_ENET_0, 2, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	{ "nand", IMX_SC_R_NAND, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 	{ "mlb", IMX_SC_R_MLB_0, 1, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 	/* AUDIO SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	{ "audio-pll0", IMX_SC_R_AUDIO_PLL_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) 	{ "audio-pll1", IMX_SC_R_AUDIO_PLL_1, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 	{ "audio-clk-0", IMX_SC_R_AUDIO_CLK_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) 	{ "audio-clk-1", IMX_SC_R_AUDIO_CLK_1, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 	{ "dma0-ch", IMX_SC_R_DMA_0_CH0, 16, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) 	{ "dma1-ch", IMX_SC_R_DMA_1_CH0, 16, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	{ "dma2-ch", IMX_SC_R_DMA_2_CH0, 5, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	{ "asrc0", IMX_SC_R_ASRC_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	{ "asrc1", IMX_SC_R_ASRC_1, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	{ "esai0", IMX_SC_R_ESAI_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	{ "spdif0", IMX_SC_R_SPDIF_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	{ "spdif1", IMX_SC_R_SPDIF_1, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) 	{ "sai", IMX_SC_R_SAI_0, 3, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 	{ "sai3", IMX_SC_R_SAI_3, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) 	{ "sai4", IMX_SC_R_SAI_4, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	{ "sai5", IMX_SC_R_SAI_5, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	{ "sai6", IMX_SC_R_SAI_6, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	{ "sai7", IMX_SC_R_SAI_7, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	{ "amix", IMX_SC_R_AMIX, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	{ "mqs0", IMX_SC_R_MQS_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) 	{ "dsp", IMX_SC_R_DSP, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 	{ "dsp-ram", IMX_SC_R_DSP_RAM, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) 	/* DMA SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 	{ "can", IMX_SC_R_CAN_0, 3, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 	{ "ftm", IMX_SC_R_FTM_0, 2, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) 	{ "lpi2c", IMX_SC_R_I2C_0, 4, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	{ "adc", IMX_SC_R_ADC_0, 1, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	{ "lcd", IMX_SC_R_LCD_0, 1, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	{ "lcd0-pwm", IMX_SC_R_LCD_0_PWM_0, 1, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	{ "lpuart", IMX_SC_R_UART_0, 4, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 	{ "lpspi", IMX_SC_R_SPI_0, 4, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	{ "irqstr_dsp", IMX_SC_R_IRQSTR_DSP, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 	/* VPU SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	{ "vpu", IMX_SC_R_VPU, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 	{ "vpu-pid", IMX_SC_R_VPU_PID0, 8, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 	{ "vpu-dec0", IMX_SC_R_VPU_DEC_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	{ "vpu-enc0", IMX_SC_R_VPU_ENC_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 	/* GPU SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	{ "gpu0-pid", IMX_SC_R_GPU_0_PID0, 4, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	/* HSIO SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 	{ "pcie-b", IMX_SC_R_PCIE_B, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 	{ "serdes-1", IMX_SC_R_SERDES_1, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	{ "hsio-gpio", IMX_SC_R_HSIO_GPIO, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 	/* MIPI SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) 	{ "mipi0", IMX_SC_R_MIPI_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 	{ "mipi0-pwm0", IMX_SC_R_MIPI_0_PWM_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) 	{ "mipi0-i2c", IMX_SC_R_MIPI_0_I2C_0, 2, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	/* LVDS SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	{ "lvds0", IMX_SC_R_LVDS_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 	/* DC SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) 	{ "dc0", IMX_SC_R_DC_0, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	{ "dc0-pll", IMX_SC_R_DC_0_PLL_0, 2, true, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) 	/* CM40 SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 	{ "cm40-i2c", IMX_SC_R_M4_0_I2C, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 	{ "cm40-intmux", IMX_SC_R_M4_0_INTMUX, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) 	{ "cm40-pid", IMX_SC_R_M4_0_PID0, 5, true, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 	{ "cm40-mu-a1", IMX_SC_R_M4_0_MU_1A, 1, false, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 	{ "cm40-lpuart", IMX_SC_R_M4_0_UART, 1, false, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	/* CM41 SS */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	{ "cm41-i2c", IMX_SC_R_M4_1_I2C, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	{ "cm41-intmux", IMX_SC_R_M4_1_INTMUX, 1, false, 0 },
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 	{ "cm41-pid", IMX_SC_R_M4_1_PID0, 5, true, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	{ "cm41-mu-a1", IMX_SC_R_M4_1_MU_1A, 1, false, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 	{ "cm41-lpuart", IMX_SC_R_M4_1_UART, 1, false, 0},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) static const struct imx_sc_pd_soc imx8qxp_scu_pd = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 	.pd_ranges = imx8qxp_scu_pd_ranges,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	.num_ranges = ARRAY_SIZE(imx8qxp_scu_pd_ranges),
^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) static struct imx_sc_ipc *pm_ipc_handle;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) static inline struct imx_sc_pm_domain *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) to_imx_sc_pd(struct generic_pm_domain *genpd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 	return container_of(genpd, struct imx_sc_pm_domain, pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) static int imx_sc_pd_power(struct generic_pm_domain *domain, bool power_on)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) 	struct imx_sc_msg_req_set_resource_power_mode msg;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201) 	struct imx_sc_rpc_msg *hdr = &msg.hdr;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202) 	struct imx_sc_pm_domain *pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205) 	pd = to_imx_sc_pd(domain);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) 	hdr->ver = IMX_SC_RPC_VERSION;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 	hdr->svc = IMX_SC_RPC_SVC_PM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) 	hdr->func = IMX_SC_PM_FUNC_SET_RESOURCE_POWER_MODE;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	hdr->size = 2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 	msg.resource = pd->rsrc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	msg.mode = power_on ? IMX_SC_PM_PW_MODE_ON : IMX_SC_PM_PW_MODE_LP;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 	ret = imx_scu_call_rpc(pm_ipc_handle, &msg, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) 		dev_err(&domain->dev, "failed to power %s resource %d ret %d\n",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 			power_on ? "up" : "off", pd->rsrc, ret);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220) 	return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223) static int imx_sc_pd_power_on(struct generic_pm_domain *domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225) 	return imx_sc_pd_power(domain, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) static int imx_sc_pd_power_off(struct generic_pm_domain *domain)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 	return imx_sc_pd_power(domain, false);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) static struct generic_pm_domain *imx_scu_pd_xlate(struct of_phandle_args *spec,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 						  void *data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 	struct generic_pm_domain *domain = ERR_PTR(-ENOENT);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 	struct genpd_onecell_data *pd_data = data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	unsigned int i;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 	for (i = 0; i < pd_data->num_domains; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 		struct imx_sc_pm_domain *sc_pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 		sc_pd = to_imx_sc_pd(pd_data->domains[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 		if (sc_pd->rsrc == spec->args[0]) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 			domain = &sc_pd->pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 			break;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 	return domain;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) static struct imx_sc_pm_domain *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) imx_scu_add_pm_domain(struct device *dev, int idx,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) 		      const struct imx_sc_pd_range *pd_ranges)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) 	struct imx_sc_pm_domain *sc_pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	if (!imx_sc_rm_is_resource_owned(pm_ipc_handle, pd_ranges->rsrc + idx))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) 	sc_pd = devm_kzalloc(dev, sizeof(*sc_pd), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 	if (!sc_pd)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) 		return ERR_PTR(-ENOMEM);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) 	sc_pd->rsrc = pd_ranges->rsrc + idx;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 	sc_pd->pd.power_off = imx_sc_pd_power_off;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) 	sc_pd->pd.power_on = imx_sc_pd_power_on;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	if (pd_ranges->postfix)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) 		snprintf(sc_pd->name, sizeof(sc_pd->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 			 "%s%i", pd_ranges->name, pd_ranges->start_from + idx);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) 		snprintf(sc_pd->name, sizeof(sc_pd->name),
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 			 "%s", pd_ranges->name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 	sc_pd->pd.name = sc_pd->name;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280) 	if (sc_pd->rsrc >= IMX_SC_R_LAST) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281) 		dev_warn(dev, "invalid pd %s rsrc id %d found",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282) 			 sc_pd->name, sc_pd->rsrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) 		devm_kfree(dev, sc_pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	ret = pm_genpd_init(&sc_pd->pd, NULL, true);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 	if (ret) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 		dev_warn(dev, "failed to init pd %s rsrc id %d",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 			 sc_pd->name, sc_pd->rsrc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 		devm_kfree(dev, sc_pd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	return sc_pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) static int imx_scu_init_pm_domains(struct device *dev,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 				    const struct imx_sc_pd_soc *pd_soc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 	const struct imx_sc_pd_range *pd_ranges = pd_soc->pd_ranges;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	struct generic_pm_domain **domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	struct genpd_onecell_data *pd_data;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	struct imx_sc_pm_domain *sc_pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) 	u32 count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 	int i, j;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 	for (i = 0; i < pd_soc->num_ranges; i++)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) 		count += pd_ranges[i].num;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312) 	domains = devm_kcalloc(dev, count, sizeof(*domains), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313) 	if (!domains)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) 	pd_data = devm_kzalloc(dev, sizeof(*pd_data), GFP_KERNEL);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 	if (!pd_data)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 		return -ENOMEM;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 	count = 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	for (i = 0; i < pd_soc->num_ranges; i++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) 		for (j = 0; j < pd_ranges[i].num; j++) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 			sc_pd = imx_scu_add_pm_domain(dev, j, &pd_ranges[i]);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 			if (IS_ERR_OR_NULL(sc_pd))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 				continue;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 			domains[count++] = &sc_pd->pd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) 			dev_dbg(dev, "added power domain %s\n", sc_pd->pd.name);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 		}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	pd_data->domains = domains;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) 	pd_data->num_domains = count;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 	pd_data->xlate = imx_scu_pd_xlate;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	of_genpd_add_provider_onecell(dev->of_node, pd_data);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) static int imx_sc_pd_probe(struct platform_device *pdev)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) 	const struct imx_sc_pd_soc *pd_soc;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	int ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	ret = imx_scu_get_handle(&pm_ipc_handle);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 	if (ret)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 		return ret;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 	pd_soc = of_device_get_match_data(&pdev->dev);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	if (!pd_soc)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 		return -ENODEV;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 	return imx_scu_init_pm_domains(&pdev->dev, pd_soc);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) static const struct of_device_id imx_sc_pd_match[] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 	{ .compatible = "fsl,imx8qxp-scu-pd", &imx8qxp_scu_pd},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 	{ .compatible = "fsl,scu-pd", &imx8qxp_scu_pd},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 	{ /* sentinel */ }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) static struct platform_driver imx_sc_pd_driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) 	.driver = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 		.name = "imx-scu-pd",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) 		.of_match_table = imx_sc_pd_match,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) 	},
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	.probe = imx_sc_pd_probe,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) builtin_platform_driver(imx_sc_pd_driver);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) MODULE_AUTHOR("Dong Aisheng <aisheng.dong@nxp.com>");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) MODULE_DESCRIPTION("IMX SCU Power Domain driver");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) MODULE_LICENSE("GPL v2");