Home | History | Annotate | Download | only in pm_service
      1 /*
      2  * Copyright (c) 2013-2017, ARM Limited and Contributors. All rights reserved.
      3  *
      4  * SPDX-License-Identifier: BSD-3-Clause
      5  */
      6 
      7 /*
      8  * APU specific definition of processors in the subsystem as well as functions
      9  * for getting information about and changing state of the APU.
     10  */
     11 
     12 #include <assert.h>
     13 #include <bakery_lock.h>
     14 #include <bl_common.h>
     15 #include <gic_common.h>
     16 #include <gicv2.h>
     17 #include <mmio.h>
     18 #include <string.h>
     19 #include <utils.h>
     20 #include "../zynqmp_def.h"
     21 #include "pm_api_sys.h"
     22 #include "pm_client.h"
     23 #include "pm_ipi.h"
     24 
     25 #define IRQ_MAX		84
     26 #define NUM_GICD_ISENABLER	((IRQ_MAX >> 5) + 1)
     27 #define UNDEFINED_CPUID		(~0)
     28 
     29 DEFINE_BAKERY_LOCK(pm_client_secure_lock);
     30 
     31 extern const struct pm_ipi apu_ipi;
     32 
     33 /* Order in pm_procs_all array must match cpu ids */
     34 static const struct pm_proc pm_procs_all[] = {
     35 	{
     36 		.node_id = NODE_APU_0,
     37 		.pwrdn_mask = APU_0_PWRCTL_CPUPWRDWNREQ_MASK,
     38 		.ipi = &apu_ipi,
     39 	},
     40 	{
     41 		.node_id = NODE_APU_1,
     42 		.pwrdn_mask = APU_1_PWRCTL_CPUPWRDWNREQ_MASK,
     43 		.ipi = &apu_ipi,
     44 	},
     45 	{
     46 		.node_id = NODE_APU_2,
     47 		.pwrdn_mask = APU_2_PWRCTL_CPUPWRDWNREQ_MASK,
     48 		.ipi = &apu_ipi,
     49 	},
     50 	{
     51 		.node_id = NODE_APU_3,
     52 		.pwrdn_mask = APU_3_PWRCTL_CPUPWRDWNREQ_MASK,
     53 		.ipi = &apu_ipi,
     54 	},
     55 };
     56 
     57 /* Interrupt to PM node ID map */
     58 static enum pm_node_id irq_node_map[IRQ_MAX + 1] = {
     59 	NODE_UNKNOWN,
     60 	NODE_UNKNOWN,
     61 	NODE_UNKNOWN,
     62 	NODE_UNKNOWN,	/* 3 */
     63 	NODE_UNKNOWN,
     64 	NODE_UNKNOWN,
     65 	NODE_UNKNOWN,
     66 	NODE_UNKNOWN,	/* 7 */
     67 	NODE_UNKNOWN,
     68 	NODE_UNKNOWN,
     69 	NODE_UNKNOWN,
     70 	NODE_UNKNOWN,	/* 11 */
     71 	NODE_UNKNOWN,
     72 	NODE_UNKNOWN,
     73 	NODE_NAND,
     74 	NODE_QSPI,	/* 15 */
     75 	NODE_GPIO,
     76 	NODE_I2C_0,
     77 	NODE_I2C_1,
     78 	NODE_SPI_0,	/* 19 */
     79 	NODE_SPI_1,
     80 	NODE_UART_0,
     81 	NODE_UART_1,
     82 	NODE_CAN_0,	/* 23 */
     83 	NODE_CAN_1,
     84 	NODE_UNKNOWN,
     85 	NODE_RTC,
     86 	NODE_RTC,	/* 27 */
     87 	NODE_UNKNOWN,
     88 	NODE_UNKNOWN,
     89 	NODE_UNKNOWN,
     90 	NODE_UNKNOWN,	/* 31 */
     91 	NODE_UNKNOWN,
     92 	NODE_UNKNOWN,
     93 	NODE_UNKNOWN,
     94 	NODE_UNKNOWN,	/* 35, NODE_IPI_APU */
     95 	NODE_TTC_0,
     96 	NODE_TTC_0,
     97 	NODE_TTC_0,
     98 	NODE_TTC_1,	/* 39 */
     99 	NODE_TTC_1,
    100 	NODE_TTC_1,
    101 	NODE_TTC_2,
    102 	NODE_TTC_2,	/* 43 */
    103 	NODE_TTC_2,
    104 	NODE_TTC_3,
    105 	NODE_TTC_3,
    106 	NODE_TTC_3,	/* 47 */
    107 	NODE_SD_0,
    108 	NODE_SD_1,
    109 	NODE_SD_0,
    110 	NODE_SD_1,	/* 51 */
    111 	NODE_UNKNOWN,
    112 	NODE_UNKNOWN,
    113 	NODE_UNKNOWN,
    114 	NODE_UNKNOWN,	/* 55 */
    115 	NODE_UNKNOWN,
    116 	NODE_ETH_0,
    117 	NODE_ETH_0,
    118 	NODE_ETH_1,	/* 59 */
    119 	NODE_ETH_1,
    120 	NODE_ETH_2,
    121 	NODE_ETH_2,
    122 	NODE_ETH_3,	/* 63 */
    123 	NODE_ETH_3,
    124 	NODE_USB_0,
    125 	NODE_USB_0,
    126 	NODE_USB_0,	/* 67 */
    127 	NODE_USB_0,
    128 	NODE_USB_0,
    129 	NODE_USB_1,
    130 	NODE_USB_1,	/* 71 */
    131 	NODE_USB_1,
    132 	NODE_USB_1,
    133 	NODE_USB_1,
    134 	NODE_USB_0,	/* 75 */
    135 	NODE_USB_0,
    136 	NODE_ADMA,
    137 	NODE_ADMA,
    138 	NODE_ADMA,	/* 79 */
    139 	NODE_ADMA,
    140 	NODE_ADMA,
    141 	NODE_ADMA,
    142 	NODE_ADMA,	/* 83 */
    143 	NODE_ADMA,
    144 };
    145 
    146 /**
    147  * irq_to_pm_node - Get PM node ID corresponding to the interrupt number
    148  * @irq:	Interrupt number
    149  *
    150  * Return:	PM node ID corresponding to the specified interrupt
    151  */
    152 static enum pm_node_id irq_to_pm_node(unsigned int irq)
    153 {
    154 	assert(irq <= IRQ_MAX);
    155 	return irq_node_map[irq];
    156 }
    157 
    158 /**
    159  * pm_client_set_wakeup_sources - Set all slaves with enabled interrupts as wake
    160  *				sources in the PMU firmware
    161  */
    162 static void pm_client_set_wakeup_sources(void)
    163 {
    164 	uint32_t reg_num;
    165 	uint8_t pm_wakeup_nodes_set[NODE_MAX];
    166 	uintptr_t isenabler1 = BASE_GICD_BASE + GICD_ISENABLER + 4;
    167 
    168 	zeromem(&pm_wakeup_nodes_set, sizeof(pm_wakeup_nodes_set));
    169 
    170 	for (reg_num = 0; reg_num < NUM_GICD_ISENABLER; reg_num++) {
    171 		uint32_t base_irq = reg_num << ISENABLER_SHIFT;
    172 		uint32_t reg = mmio_read_32(isenabler1 + (reg_num << 2));
    173 
    174 		if (!reg)
    175 			continue;
    176 
    177 		while (reg) {
    178 			enum pm_node_id node;
    179 			uint32_t idx, ret, irq, lowest_set = reg & (-reg);
    180 
    181 			idx = __builtin_ctz(lowest_set);
    182 			irq = base_irq + idx;
    183 
    184 			if (irq > IRQ_MAX)
    185 				break;
    186 
    187 			node = irq_to_pm_node(irq);
    188 			reg &= ~lowest_set;
    189 
    190 			if ((node != NODE_UNKNOWN) &&
    191 			    (!pm_wakeup_nodes_set[node])) {
    192 				ret = pm_set_wakeup_source(NODE_APU, node, 1);
    193 				pm_wakeup_nodes_set[node] = !ret;
    194 			}
    195 		}
    196 	}
    197 }
    198 
    199 /**
    200  * pm_get_proc() - returns pointer to the proc structure
    201  * @cpuid:	id of the cpu whose proc struct pointer should be returned
    202  *
    203  * Return: pointer to a proc structure if proc is found, otherwise NULL
    204  */
    205 const struct pm_proc *pm_get_proc(unsigned int cpuid)
    206 {
    207 	if (cpuid < ARRAY_SIZE(pm_procs_all))
    208 		return &pm_procs_all[cpuid];
    209 
    210 	return NULL;
    211 }
    212 
    213 /**
    214  * pm_get_proc_by_node() - returns pointer to the proc structure
    215  * @nid:	node id of the processor
    216  *
    217  * Return: pointer to a proc structure if proc is found, otherwise NULL
    218  */
    219 const struct pm_proc *pm_get_proc_by_node(enum pm_node_id nid)
    220 {
    221 	for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
    222 		if (nid == pm_procs_all[i].node_id)
    223 			return &pm_procs_all[i];
    224 	}
    225 	return NULL;
    226 }
    227 
    228 /**
    229  * pm_get_cpuid() - get the local cpu ID for a global node ID
    230  * @nid:	node id of the processor
    231  *
    232  * Return: the cpu ID (starting from 0) for the subsystem
    233  */
    234 static unsigned int pm_get_cpuid(enum pm_node_id nid)
    235 {
    236 	for (size_t i = 0; i < ARRAY_SIZE(pm_procs_all); i++) {
    237 		if (pm_procs_all[i].node_id == nid)
    238 			return i;
    239 	}
    240 	return UNDEFINED_CPUID;
    241 }
    242 
    243 const struct pm_proc *primary_proc = &pm_procs_all[0];
    244 
    245 /**
    246  * pm_client_suspend() - Client-specific suspend actions
    247  *
    248  * This function should contain any PU-specific actions
    249  * required prior to sending suspend request to PMU
    250  * Actions taken depend on the state system is suspending to.
    251  */
    252 void pm_client_suspend(const struct pm_proc *proc, unsigned int state)
    253 {
    254 	bakery_lock_get(&pm_client_secure_lock);
    255 
    256 	if (state == PM_STATE_SUSPEND_TO_RAM)
    257 		pm_client_set_wakeup_sources();
    258 
    259 	/* Set powerdown request */
    260 	mmio_write_32(APU_PWRCTL, mmio_read_32(APU_PWRCTL) | proc->pwrdn_mask);
    261 
    262 	bakery_lock_release(&pm_client_secure_lock);
    263 }
    264 
    265 
    266 /**
    267  * pm_client_abort_suspend() - Client-specific abort-suspend actions
    268  *
    269  * This function should contain any PU-specific actions
    270  * required for aborting a prior suspend request
    271  */
    272 void pm_client_abort_suspend(void)
    273 {
    274 	/* Enable interrupts at processor level (for current cpu) */
    275 	gicv2_cpuif_enable();
    276 
    277 	bakery_lock_get(&pm_client_secure_lock);
    278 
    279 	/* Clear powerdown request */
    280 	mmio_write_32(APU_PWRCTL,
    281 		 mmio_read_32(APU_PWRCTL) & ~primary_proc->pwrdn_mask);
    282 
    283 	bakery_lock_release(&pm_client_secure_lock);
    284 }
    285 
    286 /**
    287  * pm_client_wakeup() - Client-specific wakeup actions
    288  *
    289  * This function should contain any PU-specific actions
    290  * required for waking up another APU core
    291  */
    292 void pm_client_wakeup(const struct pm_proc *proc)
    293 {
    294 	unsigned int cpuid = pm_get_cpuid(proc->node_id);
    295 
    296 	if (cpuid == UNDEFINED_CPUID)
    297 		return;
    298 
    299 	bakery_lock_get(&pm_client_secure_lock);
    300 
    301 	/* clear powerdown bit for affected cpu */
    302 	uint32_t val = mmio_read_32(APU_PWRCTL);
    303 	val &= ~(proc->pwrdn_mask);
    304 	mmio_write_32(APU_PWRCTL, val);
    305 
    306 	bakery_lock_release(&pm_client_secure_lock);
    307 }
    308