Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 
0003 /* Copyright (c) 2012-2018, The Linux Foundation. All rights reserved.
0004  * Copyright (C) 2018-2020 Linaro Ltd.
0005  */
0006 
0007 #include <linux/types.h>
0008 #include <linux/io.h>
0009 #include <linux/delay.h>
0010 #include <linux/pm_runtime.h>
0011 
0012 #include "ipa.h"
0013 #include "ipa_uc.h"
0014 #include "ipa_power.h"
0015 
0016 /**
0017  * DOC:  The IPA embedded microcontroller
0018  *
0019  * The IPA incorporates a microcontroller that is able to do some additional
0020  * handling/offloading of network activity.  The current code makes
0021  * essentially no use of the microcontroller, but it still requires some
0022  * initialization.  It needs to be notified in the event the AP crashes.
0023  *
0024  * The microcontroller can generate two interrupts to the AP.  One interrupt
0025  * is used to indicate that a response to a request from the AP is available.
0026  * The other is used to notify the AP of the occurrence of an event.  In
0027  * addition, the AP can interrupt the microcontroller by writing a register.
0028  *
0029  * A 128 byte block of structured memory within the IPA SRAM is used together
0030  * with these interrupts to implement the communication interface between the
0031  * AP and the IPA microcontroller.  Each side writes data to the shared area
0032  * before interrupting its peer, which will read the written data in response
0033  * to the interrupt.  Some information found in the shared area is currently
0034  * unused.  All remaining space in the shared area is reserved, and must not
0035  * be read or written by the AP.
0036  */
0037 /* Supports hardware interface version 0x2000 */
0038 
0039 /* Delay to allow a the microcontroller to save state when crashing */
0040 #define IPA_SEND_DELAY      100 /* microseconds */
0041 
0042 /**
0043  * struct ipa_uc_mem_area - AP/microcontroller shared memory area
0044  * @command:        command code (AP->microcontroller)
0045  * @reserved0:      reserved bytes; avoid reading or writing
0046  * @command_param:  low 32 bits of command parameter (AP->microcontroller)
0047  * @command_param_hi:   high 32 bits of command parameter (AP->microcontroller)
0048  *
0049  * @response:       response code (microcontroller->AP)
0050  * @reserved1:      reserved bytes; avoid reading or writing
0051  * @response_param: response parameter (microcontroller->AP)
0052  *
0053  * @event:      event code (microcontroller->AP)
0054  * @reserved2:      reserved bytes; avoid reading or writing
0055  * @event_param:    event parameter (microcontroller->AP)
0056  *
0057  * @first_error_address: address of first error-source on SNOC
0058  * @hw_state:       state of hardware (including error type information)
0059  * @warning_counter:    counter of non-fatal hardware errors
0060  * @reserved3:      reserved bytes; avoid reading or writing
0061  * @interface_version:  hardware-reported interface version
0062  * @reserved4:      reserved bytes; avoid reading or writing
0063  *
0064  * A shared memory area at the base of IPA resident memory is used for
0065  * communication with the microcontroller.  The region is 128 bytes in
0066  * size, but only the first 40 bytes (structured this way) are used.
0067  */
0068 struct ipa_uc_mem_area {
0069     u8 command;     /* enum ipa_uc_command */
0070     u8 reserved0[3];
0071     __le32 command_param;
0072     __le32 command_param_hi;
0073     u8 response;        /* enum ipa_uc_response */
0074     u8 reserved1[3];
0075     __le32 response_param;
0076     u8 event;       /* enum ipa_uc_event */
0077     u8 reserved2[3];
0078 
0079     __le32 event_param;
0080     __le32 first_error_address;
0081     u8 hw_state;
0082     u8 warning_counter;
0083     __le16 reserved3;
0084     __le16 interface_version;
0085     __le16 reserved4;
0086 };
0087 
0088 /** enum ipa_uc_command - commands from the AP to the microcontroller */
0089 enum ipa_uc_command {
0090     IPA_UC_COMMAND_NO_OP        = 0x0,
0091     IPA_UC_COMMAND_UPDATE_FLAGS = 0x1,
0092     IPA_UC_COMMAND_DEBUG_RUN_TEST   = 0x2,
0093     IPA_UC_COMMAND_DEBUG_GET_INFO   = 0x3,
0094     IPA_UC_COMMAND_ERR_FATAL    = 0x4,
0095     IPA_UC_COMMAND_CLK_GATE     = 0x5,
0096     IPA_UC_COMMAND_CLK_UNGATE   = 0x6,
0097     IPA_UC_COMMAND_MEMCPY       = 0x7,
0098     IPA_UC_COMMAND_RESET_PIPE   = 0x8,
0099     IPA_UC_COMMAND_REG_WRITE    = 0x9,
0100     IPA_UC_COMMAND_GSI_CH_EMPTY = 0xa,
0101 };
0102 
0103 /** enum ipa_uc_response - microcontroller response codes */
0104 enum ipa_uc_response {
0105     IPA_UC_RESPONSE_NO_OP       = 0x0,
0106     IPA_UC_RESPONSE_INIT_COMPLETED  = 0x1,
0107     IPA_UC_RESPONSE_CMD_COMPLETED   = 0x2,
0108     IPA_UC_RESPONSE_DEBUG_GET_INFO  = 0x3,
0109 };
0110 
0111 /** enum ipa_uc_event - common cpu events reported by the microcontroller */
0112 enum ipa_uc_event {
0113     IPA_UC_EVENT_NO_OP      = 0x0,
0114     IPA_UC_EVENT_ERROR      = 0x1,
0115     IPA_UC_EVENT_LOG_INFO       = 0x2,
0116 };
0117 
0118 static struct ipa_uc_mem_area *ipa_uc_shared(struct ipa *ipa)
0119 {
0120     const struct ipa_mem *mem = ipa_mem_find(ipa, IPA_MEM_UC_SHARED);
0121     u32 offset = ipa->mem_offset + mem->offset;
0122 
0123     return ipa->mem_virt + offset;
0124 }
0125 
0126 /* Microcontroller event IPA interrupt handler */
0127 static void ipa_uc_event_handler(struct ipa *ipa, enum ipa_irq_id irq_id)
0128 {
0129     struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa);
0130     struct device *dev = &ipa->pdev->dev;
0131 
0132     if (shared->event == IPA_UC_EVENT_ERROR)
0133         dev_err(dev, "microcontroller error event\n");
0134     else if (shared->event != IPA_UC_EVENT_LOG_INFO)
0135         dev_err(dev, "unsupported microcontroller event %u\n",
0136             shared->event);
0137     /* The LOG_INFO event can be safely ignored */
0138 }
0139 
0140 /* Microcontroller response IPA interrupt handler */
0141 static void ipa_uc_response_hdlr(struct ipa *ipa, enum ipa_irq_id irq_id)
0142 {
0143     struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa);
0144     struct device *dev = &ipa->pdev->dev;
0145 
0146     /* An INIT_COMPLETED response message is sent to the AP by the
0147      * microcontroller when it is operational.  Other than this, the AP
0148      * should only receive responses from the microcontroller when it has
0149      * sent it a request message.
0150      *
0151      * We can drop the power reference taken in ipa_uc_power() once we
0152      * know the microcontroller has finished its initialization.
0153      */
0154     switch (shared->response) {
0155     case IPA_UC_RESPONSE_INIT_COMPLETED:
0156         if (ipa->uc_powered) {
0157             ipa->uc_loaded = true;
0158             ipa_power_retention(ipa, true);
0159             pm_runtime_mark_last_busy(dev);
0160             (void)pm_runtime_put_autosuspend(dev);
0161             ipa->uc_powered = false;
0162         } else {
0163             dev_warn(dev, "unexpected init_completed response\n");
0164         }
0165         break;
0166     default:
0167         dev_warn(dev, "unsupported microcontroller response %u\n",
0168              shared->response);
0169         break;
0170     }
0171 }
0172 
0173 /* Configure the IPA microcontroller subsystem */
0174 void ipa_uc_config(struct ipa *ipa)
0175 {
0176     ipa->uc_powered = false;
0177     ipa->uc_loaded = false;
0178     ipa_interrupt_add(ipa->interrupt, IPA_IRQ_UC_0, ipa_uc_event_handler);
0179     ipa_interrupt_add(ipa->interrupt, IPA_IRQ_UC_1, ipa_uc_response_hdlr);
0180 }
0181 
0182 /* Inverse of ipa_uc_config() */
0183 void ipa_uc_deconfig(struct ipa *ipa)
0184 {
0185     struct device *dev = &ipa->pdev->dev;
0186 
0187     ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_1);
0188     ipa_interrupt_remove(ipa->interrupt, IPA_IRQ_UC_0);
0189     if (ipa->uc_loaded)
0190         ipa_power_retention(ipa, false);
0191 
0192     if (!ipa->uc_powered)
0193         return;
0194 
0195     pm_runtime_mark_last_busy(dev);
0196     (void)pm_runtime_put_autosuspend(dev);
0197 }
0198 
0199 /* Take a proxy power reference for the microcontroller */
0200 void ipa_uc_power(struct ipa *ipa)
0201 {
0202     static bool already;
0203     struct device *dev;
0204     int ret;
0205 
0206     if (already)
0207         return;
0208     already = true;     /* Only do this on first boot */
0209 
0210     /* This power reference dropped in ipa_uc_response_hdlr() above */
0211     dev = &ipa->pdev->dev;
0212     ret = pm_runtime_get_sync(dev);
0213     if (ret < 0) {
0214         pm_runtime_put_noidle(dev);
0215         dev_err(dev, "error %d getting proxy power\n", ret);
0216     } else {
0217         ipa->uc_powered = true;
0218     }
0219 }
0220 
0221 /* Send a command to the microcontroller */
0222 static void send_uc_command(struct ipa *ipa, u32 command, u32 command_param)
0223 {
0224     struct ipa_uc_mem_area *shared = ipa_uc_shared(ipa);
0225     u32 offset;
0226     u32 val;
0227 
0228     /* Fill in the command data */
0229     shared->command = command;
0230     shared->command_param = cpu_to_le32(command_param);
0231     shared->command_param_hi = 0;
0232     shared->response = 0;
0233     shared->response_param = 0;
0234 
0235     /* Use an interrupt to tell the microcontroller the command is ready */
0236     val = u32_encode_bits(1, UC_INTR_FMASK);
0237     offset = ipa_reg_irq_uc_offset(ipa->version);
0238     iowrite32(val, ipa->reg_virt + offset);
0239 }
0240 
0241 /* Tell the microcontroller the AP is shutting down */
0242 void ipa_uc_panic_notifier(struct ipa *ipa)
0243 {
0244     if (!ipa->uc_loaded)
0245         return;
0246 
0247     send_uc_command(ipa, IPA_UC_COMMAND_ERR_FATAL, 0);
0248 
0249     /* give uc enough time to save state */
0250     udelay(IPA_SEND_DELAY);
0251 }