1*a646d6ecSAlex Elder // SPDX-License-Identifier: GPL-2.0 2*a646d6ecSAlex Elder 3*a646d6ecSAlex Elder /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved. 4*a646d6ecSAlex Elder * Copyright (C) 2018-2020 Linaro Ltd. 5*a646d6ecSAlex Elder */ 6*a646d6ecSAlex Elder 7*a646d6ecSAlex Elder #include <linux/types.h> 8*a646d6ecSAlex Elder #include <linux/io.h> 9*a646d6ecSAlex Elder #include <linux/delay.h> 10*a646d6ecSAlex Elder 11*a646d6ecSAlex Elder #include "ipa.h" 12*a646d6ecSAlex Elder #include "ipa_clock.h" 13*a646d6ecSAlex Elder #include "ipa_uc.h" 14*a646d6ecSAlex Elder 15*a646d6ecSAlex Elder /** 16*a646d6ecSAlex Elder * DOC: The IPA embedded microcontroller 17*a646d6ecSAlex Elder * 18*a646d6ecSAlex Elder * The IPA incorporates a microcontroller that is able to do some additional 19*a646d6ecSAlex Elder * handling/offloading of network activity. The current code makes 20*a646d6ecSAlex Elder * essentially no use of the microcontroller, but it still requires some 21*a646d6ecSAlex Elder * initialization. It needs to be notified in the event the AP crashes. 22*a646d6ecSAlex Elder * 23*a646d6ecSAlex Elder * The microcontroller can generate two interrupts to the AP. One interrupt 24*a646d6ecSAlex Elder * is used to indicate that a response to a request from the AP is available. 25*a646d6ecSAlex Elder * The other is used to notify the AP of the occurrence of an event. In 26*a646d6ecSAlex Elder * addition, the AP can interrupt the microcontroller by writing a register. 27*a646d6ecSAlex Elder * 28*a646d6ecSAlex Elder * A 128 byte block of structured memory within the IPA SRAM is used together 29*a646d6ecSAlex Elder * with these interrupts to implement the communication interface between the 30*a646d6ecSAlex Elder * AP and the IPA microcontroller. Each side writes data to the shared area 31*a646d6ecSAlex Elder * before interrupting its peer, which will read the written data in response 32*a646d6ecSAlex Elder * to the interrupt. Some information found in the shared area is currently 33*a646d6ecSAlex Elder * unused. All remaining space in the shared area is reserved, and must not 34*a646d6ecSAlex Elder * be read or written by the AP. 35*a646d6ecSAlex Elder */ 36*a646d6ecSAlex Elder /* Supports hardware interface version 0x2000 */ 37*a646d6ecSAlex Elder 38*a646d6ecSAlex Elder /* Offset relative to the base of the IPA shared address space of the 39*a646d6ecSAlex Elder * shared region used for communication with the microcontroller. The 40*a646d6ecSAlex Elder * region is 128 bytes in size, but only the first 40 bytes are used. 41*a646d6ecSAlex Elder */ 42*a646d6ecSAlex Elder #define IPA_MEM_UC_OFFSET 0x0000 43*a646d6ecSAlex Elder 44*a646d6ecSAlex Elder /* Delay to allow a the microcontroller to save state when crashing */ 45*a646d6ecSAlex Elder #define IPA_SEND_DELAY 100 /* microseconds */ 46*a646d6ecSAlex Elder 47*a646d6ecSAlex Elder /** 48*a646d6ecSAlex Elder * struct ipa_uc_mem_area - AP/microcontroller shared memory area 49*a646d6ecSAlex Elder * @command: command code (AP->microcontroller) 50*a646d6ecSAlex Elder * @command_param: low 32 bits of command parameter (AP->microcontroller) 51*a646d6ecSAlex Elder * @command_param_hi: high 32 bits of command parameter (AP->microcontroller) 52*a646d6ecSAlex Elder * 53*a646d6ecSAlex Elder * @response: response code (microcontroller->AP) 54*a646d6ecSAlex Elder * @response_param: response parameter (microcontroller->AP) 55*a646d6ecSAlex Elder * 56*a646d6ecSAlex Elder * @event: event code (microcontroller->AP) 57*a646d6ecSAlex Elder * @event_param: event parameter (microcontroller->AP) 58*a646d6ecSAlex Elder * 59*a646d6ecSAlex Elder * @first_error_address: address of first error-source on SNOC 60*a646d6ecSAlex Elder * @hw_state: state of hardware (including error type information) 61*a646d6ecSAlex Elder * @warning_counter: counter of non-fatal hardware errors 62*a646d6ecSAlex Elder * @interface_version: hardware-reported interface version 63*a646d6ecSAlex Elder */ 64*a646d6ecSAlex Elder struct ipa_uc_mem_area { 65*a646d6ecSAlex Elder u8 command; /* enum ipa_uc_command */ 66*a646d6ecSAlex Elder u8 reserved0[3]; 67*a646d6ecSAlex Elder __le32 command_param; 68*a646d6ecSAlex Elder __le32 command_param_hi; 69*a646d6ecSAlex Elder u8 response; /* enum ipa_uc_response */ 70*a646d6ecSAlex Elder u8 reserved1[3]; 71*a646d6ecSAlex Elder __le32 response_param; 72*a646d6ecSAlex Elder u8 event; /* enum ipa_uc_event */ 73*a646d6ecSAlex Elder u8 reserved2[3]; 74*a646d6ecSAlex Elder 75*a646d6ecSAlex Elder __le32 event_param; 76*a646d6ecSAlex Elder __le32 first_error_address; 77*a646d6ecSAlex Elder u8 hw_state; 78*a646d6ecSAlex Elder u8 warning_counter; 79*a646d6ecSAlex Elder __le16 reserved3; 80*a646d6ecSAlex Elder __le16 interface_version; 81*a646d6ecSAlex Elder __le16 reserved4; 82*a646d6ecSAlex Elder }; 83*a646d6ecSAlex Elder 84*a646d6ecSAlex Elder /** enum ipa_uc_command - commands from the AP to the microcontroller */ 85*a646d6ecSAlex Elder enum ipa_uc_command { 86*a646d6ecSAlex Elder IPA_UC_COMMAND_NO_OP = 0, 87*a646d6ecSAlex Elder IPA_UC_COMMAND_UPDATE_FLAGS = 1, 88*a646d6ecSAlex Elder IPA_UC_COMMAND_DEBUG_RUN_TEST = 2, 89*a646d6ecSAlex Elder IPA_UC_COMMAND_DEBUG_GET_INFO = 3, 90*a646d6ecSAlex Elder IPA_UC_COMMAND_ERR_FATAL = 4, 91*a646d6ecSAlex Elder IPA_UC_COMMAND_CLK_GATE = 5, 92*a646d6ecSAlex Elder IPA_UC_COMMAND_CLK_UNGATE = 6, 93*a646d6ecSAlex Elder IPA_UC_COMMAND_MEMCPY = 7, 94*a646d6ecSAlex Elder IPA_UC_COMMAND_RESET_PIPE = 8, 95*a646d6ecSAlex Elder IPA_UC_COMMAND_REG_WRITE = 9, 96*a646d6ecSAlex Elder IPA_UC_COMMAND_GSI_CH_EMPTY = 10, 97*a646d6ecSAlex Elder }; 98*a646d6ecSAlex Elder 99*a646d6ecSAlex Elder /** enum ipa_uc_response - microcontroller response codes */ 100*a646d6ecSAlex Elder enum ipa_uc_response { 101*a646d6ecSAlex Elder IPA_UC_RESPONSE_NO_OP = 0, 102*a646d6ecSAlex Elder IPA_UC_RESPONSE_INIT_COMPLETED = 1, 103*a646d6ecSAlex Elder IPA_UC_RESPONSE_CMD_COMPLETED = 2, 104*a646d6ecSAlex Elder IPA_UC_RESPONSE_DEBUG_GET_INFO = 3, 105*a646d6ecSAlex Elder }; 106*a646d6ecSAlex Elder 107*a646d6ecSAlex Elder /** enum ipa_uc_event - common cpu events reported by the microcontroller */ 108*a646d6ecSAlex Elder enum ipa_uc_event { 109*a646d6ecSAlex Elder IPA_UC_EVENT_NO_OP = 0, 110*a646d6ecSAlex Elder IPA_UC_EVENT_ERROR = 1, 111*a646d6ecSAlex Elder IPA_UC_EVENT_LOG_INFO = 2, 112*a646d6ecSAlex Elder }; 113*a646d6ecSAlex Elder 114*a646d6ecSAlex Elder static struct ipa_uc_mem_area *ipa_uc_shared(struct ipa *ipa) 115*a646d6ecSAlex Elder { 116*a646d6ecSAlex Elder u32 offset = ipa->mem_offset + ipa->mem[IPA_MEM_UC_SHARED].offset; 117*a646d6ecSAlex Elder 118*a646d6ecSAlex Elder return ipa->mem_virt + offset; 119*a646d6ecSAlex Elder } 120*a646d6ecSAlex Elder 121*a646d6ecSAlex Elder /* Microcontroller event IPA interrupt handler */ 122*a646d6ecSAlex Elder static void ipa_uc_event_handler(struct ipa *ipa, enum ipa_irq_id irq_id) 123*a646d6ecSAlex Elder { 124*a646d6ecSAlex Elder struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa); 125*a646d6ecSAlex Elder struct device *dev = &ipa->pdev->dev; 126*a646d6ecSAlex Elder 127*a646d6ecSAlex Elder if (shared->event == IPA_UC_EVENT_ERROR) 128*a646d6ecSAlex Elder dev_err(dev, "microcontroller error event\n"); 129*a646d6ecSAlex Elder else 130*a646d6ecSAlex Elder dev_err(dev, "unsupported microcontroller event %hhu\n", 131*a646d6ecSAlex Elder shared->event); 132*a646d6ecSAlex Elder } 133*a646d6ecSAlex Elder 134*a646d6ecSAlex Elder /* Microcontroller response IPA interrupt handler */ 135*a646d6ecSAlex Elder static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id) 136*a646d6ecSAlex Elder { 137*a646d6ecSAlex Elder struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa); 138*a646d6ecSAlex Elder 139*a646d6ecSAlex Elder /* An INIT_COMPLETED response message is sent to the AP by the 140*a646d6ecSAlex Elder * microcontroller when it is operational. Other than this, the AP 141*a646d6ecSAlex Elder * should only receive responses from the microcontroller when it has 142*a646d6ecSAlex Elder * sent it a request message. 143*a646d6ecSAlex Elder * 144*a646d6ecSAlex Elder * We can drop the clock reference taken in ipa_uc_init() once we 145*a646d6ecSAlex Elder * know the microcontroller has finished its initialization. 146*a646d6ecSAlex Elder */ 147*a646d6ecSAlex Elder switch (shared->response) { 148*a646d6ecSAlex Elder case IPA_UC_RESPONSE_INIT_COMPLETED: 149*a646d6ecSAlex Elder ipa->uc_loaded = true; 150*a646d6ecSAlex Elder ipa_clock_put(ipa); 151*a646d6ecSAlex Elder break; 152*a646d6ecSAlex Elder default: 153*a646d6ecSAlex Elder dev_warn(&ipa->pdev->dev, 154*a646d6ecSAlex Elder "unsupported microcontroller response %hhu\n", 155*a646d6ecSAlex Elder shared->response); 156*a646d6ecSAlex Elder break; 157*a646d6ecSAlex Elder } 158*a646d6ecSAlex Elder } 159*a646d6ecSAlex Elder 160*a646d6ecSAlex Elder /* ipa_uc_setup() - Set up the microcontroller */ 161*a646d6ecSAlex Elder void ipa_uc_setup(struct ipa *ipa) 162*a646d6ecSAlex Elder { 163*a646d6ecSAlex Elder /* The microcontroller needs the IPA clock running until it has 164*a646d6ecSAlex Elder * completed its initialization. It signals this by sending an 165*a646d6ecSAlex Elder * INIT_COMPLETED response message to the AP. This could occur after 166*a646d6ecSAlex Elder * we have finished doing the rest of the IPA initialization, so we 167*a646d6ecSAlex Elder * need to take an extra "proxy" reference, and hold it until we've 168*a646d6ecSAlex Elder * received that signal. (This reference is dropped in 169*a646d6ecSAlex Elder * ipa_uc_response_hdlr(), above.) 170*a646d6ecSAlex Elder */ 171*a646d6ecSAlex Elder ipa_clock_get(ipa); 172*a646d6ecSAlex Elder 173*a646d6ecSAlex Elder ipa->uc_loaded = false; 174*a646d6ecSAlex Elder ipa_interrupt_add(ipa->interrupt, IPA_IRQ_UC_0, ipa_uc_event_handler); 175*a646d6ecSAlex Elder ipa_interrupt_add(ipa->interrupt, IPA_IRQ_UC_1, ipa_uc_response_hdlr); 176*a646d6ecSAlex Elder } 177*a646d6ecSAlex Elder 178*a646d6ecSAlex Elder /* Inverse of ipa_uc_setup() */ 179*a646d6ecSAlex Elder void ipa_uc_teardown(struct ipa *ipa) 180*a646d6ecSAlex Elder { 181*a646d6ecSAlex Elder ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1); 182*a646d6ecSAlex Elder ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0); 183*a646d6ecSAlex Elder if (!ipa->uc_loaded) 184*a646d6ecSAlex Elder ipa_clock_put(ipa); 185*a646d6ecSAlex Elder } 186*a646d6ecSAlex Elder 187*a646d6ecSAlex Elder /* Send a command to the microcontroller */ 188*a646d6ecSAlex Elder static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param) 189*a646d6ecSAlex Elder { 190*a646d6ecSAlex Elder struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa); 191*a646d6ecSAlex Elder 192*a646d6ecSAlex Elder shared->command = command; 193*a646d6ecSAlex Elder shared->command_param = cpu_to_le32(command_param); 194*a646d6ecSAlex Elder shared->command_param_hi = 0; 195*a646d6ecSAlex Elder shared->response = 0; 196*a646d6ecSAlex Elder shared->response_param = 0; 197*a646d6ecSAlex Elder 198*a646d6ecSAlex Elder iowrite32(1, ipa->reg_virt + IPA_REG_IRQ_UC_OFFSET); 199*a646d6ecSAlex Elder } 200*a646d6ecSAlex Elder 201*a646d6ecSAlex Elder /* Tell the microcontroller the AP is shutting down */ 202*a646d6ecSAlex Elder void ipa_uc_panic_notifier(struct ipa *ipa) 203*a646d6ecSAlex Elder { 204*a646d6ecSAlex Elder if (!ipa->uc_loaded) 205*a646d6ecSAlex Elder return; 206*a646d6ecSAlex Elder 207*a646d6ecSAlex Elder send_uc_command(ipa, IPA_UC_COMMAND_ERR_FATAL, 0); 208*a646d6ecSAlex Elder 209*a646d6ecSAlex Elder /* give uc enough time to save state */ 210*a646d6ecSAlex Elder udelay(IPA_SEND_DELAY); 211*a646d6ecSAlex Elder } 212