123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791 |
- /* Copyright (c) 2017-2018, The Linux Foundation. All rights reserved.
- *
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 2 and
- * only version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
- #include <linux/kernel.h>
- #include <linux/err.h>
- #include <linux/io.h>
- #include <linux/module.h>
- #include <linux/platform_device.h>
- #include <linux/of.h>
- #include <linux/interrupt.h>
- #include <linux/of_gpio.h>
- #include <linux/delay.h>
- #include <linux/slab.h>
- #include <linux/dma-mapping.h>
- #include <linux/reboot.h>
- #include <soc/qcom/subsystem_restart.h>
- #include <soc/qcom/ramdump.h>
- #include <soc/qcom/subsystem_notif.h>
- #include <linux/highmem.h>
- #include "peripheral-loader.h"
- #include "../../misc/qseecom_kernel.h"
- #include "pil_bg_intf.h"
- #include "bgcom_interface.h"
- #define INVALID_GPIO -1
- #define NUM_GPIOS 4
- #define SECURE_APP "bgapp"
- #define desc_to_data(d) container_of(d, struct pil_bg_data, desc)
- #define subsys_to_data(d) container_of(d, struct pil_bg_data, subsys_desc)
- #define BG_RAMDUMP_SZ 0x00102000
- #define BG_CRASH_IN_TWM -2
- /**
- * struct pil_bg_data
- * @qseecom_handle: handle of TZ app
- * @bg_queue: private queue to schedule worker threads for bottom half
- * @restart_work: work struct for executing ssr
- * @reboot_blk: notification block for reboot event
- * @subsys_desc: subsystem descriptor
- * @subsys: subsystem device pointer
- * @gpios: array to hold all gpio handle
- * @desc: PIL descriptor
- * @address_fw: address where firmware binaries loaded
- * @ramdump_dev: ramdump device pointer
- * @size_fw: size of bg firmware binaries
- * @errfatal_irq: irq number to indicate bg crash or shutdown
- * @status_irq: irq to indicate bg status
- * @app_status: status of tz app loading
- * @is_ready: Is BG chip up
- * @err_ready: The error ready signal
- */
- struct pil_bg_data {
- struct qseecom_handle *qseecom_handle;
- struct workqueue_struct *bg_queue;
- struct work_struct restart_work;
- struct notifier_block reboot_blk;
- struct subsys_desc subsys_desc;
- struct subsys_device *subsys;
- unsigned int gpios[NUM_GPIOS];
- int errfatal_irq;
- int status_irq;
- struct pil_desc desc;
- phys_addr_t address_fw;
- void *ramdump_dev;
- u32 cmd_status;
- size_t size_fw;
- int app_status;
- bool is_ready;
- struct completion err_ready;
- };
- static irqreturn_t bg_status_change(int irq, void *dev_id);
- /**
- * bg_app_shutdown_notify() - Toggle AP2BG err fatal gpio when
- * called by SSR framework.
- * @subsys: struct containing private BG data.
- *
- * Return: none.
- */
- static void bg_app_shutdown_notify(const struct subsys_desc *subsys)
- {
- struct pil_bg_data *bg_data = subsys_to_data(subsys);
- /* Disable irq if already BG is up */
- if (bg_data->is_ready) {
- disable_irq(bg_data->status_irq);
- disable_irq(bg_data->errfatal_irq);
- bg_data->is_ready = false;
- }
- /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */
- if (gpio_is_valid(bg_data->gpios[2])) {
- pr_debug("Sending Apps shutdown signal\n");
- gpio_set_value(bg_data->gpios[2], 1);
- }
- }
- /**
- * bg_app_reboot_notify() - Toggle AP2BG err fatal gpio.
- * @nb: struct containing private BG data.
- *
- * Return: NOTIFY_DONE indicating success.
- */
- static int bg_app_reboot_notify(struct notifier_block *nb,
- unsigned long code, void *unused)
- {
- struct pil_bg_data *bg_data = container_of(nb,
- struct pil_bg_data, reboot_blk);
- /* Disable irq if already BG is up */
- if (bg_data->is_ready) {
- disable_irq(bg_data->status_irq);
- disable_irq(bg_data->errfatal_irq);
- bg_data->is_ready = false;
- }
- /* Toggle AP2BG err fatal gpio here to inform apps err fatal event */
- if (gpio_is_valid(bg_data->gpios[2])) {
- pr_debug("Sending reboot signal\n");
- gpio_set_value(bg_data->gpios[2], 1);
- }
- return NOTIFY_DONE;
- }
- /**
- * get_cmd_rsp_buffers() - Function sets cmd & rsp buffer pointers and
- * aligns buffer lengths
- * @hdl: index of qseecom_handle
- * @cmd: req buffer - set to qseecom_handle.sbuf
- * @cmd_len: ptr to req buffer len
- * @rsp: rsp buffer - set to qseecom_handle.sbuf + offset
- * @rsp_len: ptr to rsp buffer len
- *
- * Return: Success always .
- */
- static int get_cmd_rsp_buffers(struct qseecom_handle *handle, void **cmd,
- uint32_t *cmd_len, void **rsp, uint32_t *rsp_len)
- {
- *cmd = handle->sbuf;
- if (*cmd_len & QSEECOM_ALIGN_MASK)
- *cmd_len = QSEECOM_ALIGN(*cmd_len);
- *rsp = handle->sbuf + *cmd_len;
- if (*rsp_len & QSEECOM_ALIGN_MASK)
- *rsp_len = QSEECOM_ALIGN(*rsp_len);
- return 0;
- }
- /**
- * pil_load_bg_tzapp() - Called to load TZ app.
- * @pbd: struct containing private BG data.
- *
- * Return: 0 on success. Error code on failure.
- */
- static int pil_load_bg_tzapp(struct pil_bg_data *pbd)
- {
- int rc;
- /* return success if already loaded */
- if (pbd->qseecom_handle && !pbd->app_status)
- return 0;
- /* Load the APP */
- rc = qseecom_start_app(&pbd->qseecom_handle, SECURE_APP, SZ_4K);
- if (rc < 0) {
- dev_err(pbd->desc.dev, "BG TZ app load failure\n");
- pbd->app_status = RESULT_FAILURE;
- return -EIO;
- }
- pbd->app_status = RESULT_SUCCESS;
- return 0;
- }
- /**
- * bgpil_tzapp_comm() - Function called to communicate with TZ APP.
- * @req: struct containing command and parameters.
- *
- * Return: 0 on success. Error code on failure.
- */
- static long bgpil_tzapp_comm(struct pil_bg_data *pbd,
- struct tzapp_bg_req *req)
- {
- struct tzapp_bg_req *bg_tz_req;
- struct tzapp_bg_rsp *bg_tz_rsp;
- int rc, req_len, rsp_len;
- /* Fill command structure */
- req_len = sizeof(struct tzapp_bg_req);
- rsp_len = sizeof(struct tzapp_bg_rsp);
- rc = get_cmd_rsp_buffers(pbd->qseecom_handle,
- (void **)&bg_tz_req, &req_len,
- (void **)&bg_tz_rsp, &rsp_len);
- if (rc)
- goto end;
- bg_tz_req->tzapp_bg_cmd = req->tzapp_bg_cmd;
- bg_tz_req->address_fw = req->address_fw;
- bg_tz_req->size_fw = req->size_fw;
- rc = qseecom_send_command(pbd->qseecom_handle,
- (void *)bg_tz_req, req_len, (void *)bg_tz_rsp, rsp_len);
- pr_debug("BG PIL qseecom returned with value 0x%x and status 0x%x\n",
- rc, bg_tz_rsp->status);
- if (rc || bg_tz_rsp->status)
- pbd->cmd_status = bg_tz_rsp->status;
- else
- pbd->cmd_status = 0;
- end:
- return rc;
- }
- /**
- * wait_for_err_ready() - Called in power_up to wait for error ready.
- * Signal waiting function.
- * @bg_data: BG PIL private structure.
- *
- * Return: 0 on success. Error code on failure.
- */
- static int wait_for_err_ready(struct pil_bg_data *bg_data)
- {
- int ret;
- if ((!bg_data->status_irq))
- return 0;
- ret = wait_for_completion_timeout(&bg_data->err_ready,
- msecs_to_jiffies(10000));
- if (!ret) {
- pr_err("[%s]: Error ready timed out\n", bg_data->desc.name);
- return -ETIMEDOUT;
- }
- return 0;
- }
- /**
- * bg_powerup() - Called by SSR framework on userspace invocation.
- * does load tz app and call peripheral loader.
- * @subsys: struct containing private BG data.
- *
- * Return: 0 on success. Error code on failure.
- */
- static int bg_powerup(const struct subsys_desc *subsys)
- {
- struct pil_bg_data *bg_data = subsys_to_data(subsys);
- int ret;
- init_completion(&bg_data->err_ready);
- if (!bg_data->qseecom_handle) {
- ret = pil_load_bg_tzapp(bg_data);
- if (ret) {
- dev_err(bg_data->desc.dev,
- "%s: BG TZ app load failure\n",
- __func__);
- return ret;
- }
- }
- pr_debug("bgapp loaded\n");
- bg_data->desc.fw_name = subsys->fw_name;
- ret = devm_request_irq(bg_data->desc.dev, bg_data->status_irq,
- bg_status_change,
- IRQF_TRIGGER_RISING | IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
- "bg2ap_status", bg_data);
- if (ret < 0) {
- dev_err(bg_data->desc.dev,
- "%s: BG2AP_STATUS IRQ#%d re registration failed, err=%d",
- __func__, bg_data->status_irq, ret);
- return ret;
- }
- disable_irq(bg_data->status_irq);
- /* Enable status and err fatal irqs */
- ret = pil_boot(&bg_data->desc);
- if (ret) {
- dev_err(bg_data->desc.dev,
- "%s: BG PIL Boot failed\n", __func__);
- return ret;
- }
- enable_irq(bg_data->status_irq);
- ret = wait_for_err_ready(bg_data);
- if (ret) {
- dev_err(bg_data->desc.dev,
- "[%s:%d]: Timed out waiting for error ready: %s!\n",
- current->comm, current->pid, bg_data->desc.name);
- return ret;
- }
- return ret;
- }
- /**
- * bg_shutdown() - Called by SSR framework on userspace invocation.
- * disable status interrupt to avoid spurious signal during PRM exit.
- * @subsys: struct containing private BG data.
- * @force_stop: unused
- *
- * Return: always success
- */
- static int bg_shutdown(const struct subsys_desc *subsys, bool force_stop)
- {
- struct pil_bg_data *bg_data = subsys_to_data(subsys);
- if (bg_data->is_ready) {
- disable_irq(bg_data->status_irq);
- devm_free_irq(bg_data->desc.dev, bg_data->status_irq, bg_data);
- disable_irq(bg_data->errfatal_irq);
- bg_data->is_ready = false;
- }
- return 0;
- }
- /**
- * bg_auth_metadata() - Called by Peripheral loader framework
- * send command to tz app for authentication of metadata.
- * @pil: pil descriptor.
- * @metadata: metadata load address
- * @size: size of metadata
- *
- * Return: 0 on success. Error code on failure.
- */
- static int bg_auth_metadata(struct pil_desc *pil,
- const u8 *metadata, size_t size,
- phys_addr_t addr, void *sz)
- {
- struct pil_bg_data *bg_data = desc_to_data(pil);
- struct tzapp_bg_req bg_tz_req;
- void *mdata_buf;
- dma_addr_t mdata_phys;
- unsigned long attrs = 0;
- struct device dev = {0};
- int ret;
- arch_setup_dma_ops(&dev, 0, 0, NULL, 0);
- dev.coherent_dma_mask = DMA_BIT_MASK(sizeof(dma_addr_t) * 8);
- attrs |= DMA_ATTR_STRONGLY_ORDERED;
- mdata_buf = dma_alloc_attrs(&dev, size,
- &mdata_phys, GFP_KERNEL, attrs);
- if (!mdata_buf) {
- pr_err("BG_PIL: Allocation for metadata failed.\n");
- return -ENOMEM;
- }
- /* Make sure there are no mappings in PKMAP and fixmap */
- kmap_flush_unused();
- kmap_atomic_flush_unused();
- memcpy(mdata_buf, metadata, size);
- bg_tz_req.tzapp_bg_cmd = BGPIL_AUTH_MDT;
- bg_tz_req.address_fw = (phys_addr_t)mdata_phys;
- bg_tz_req.size_fw = size;
- ret = bgpil_tzapp_comm(bg_data, &bg_tz_req);
- if (ret || bg_data->cmd_status) {
- dev_err(pil->dev,
- "%s: BGPIL_AUTH_MDT qseecom call failed\n",
- __func__);
- return bg_data->cmd_status;
- }
- dma_free_attrs(&dev, size, mdata_buf, mdata_phys, attrs);
- pr_debug("BG MDT Authenticated\n");
- return 0;
- }
- /**
- * bg_get_firmware_addr() - Called by Peripheral loader framework
- * to get address and size of bg firmware binaries.
- * @pil: pil descriptor.
- * @addr: fw load address
- * @size: size of fw
- *
- * Return: 0 on success.
- */
- static int bg_get_firmware_addr(struct pil_desc *pil,
- phys_addr_t addr, size_t size)
- {
- struct pil_bg_data *bg_data = desc_to_data(pil);
- bg_data->address_fw = addr;
- bg_data->size_fw = size;
- pr_debug("BG PIL loads firmware blobs at 0x%x with size 0x%x\n",
- addr, size);
- return 0;
- }
- /**
- * bg_auth_and_xfer() - Called by Peripheral loader framework
- * to signal tz app to authenticate and boot bg chip.
- * @pil: pil descriptor.
- *
- * Return: 0 on success. Error code on failure.
- */
- static int bg_auth_and_xfer(struct pil_desc *pil)
- {
- struct pil_bg_data *bg_data = desc_to_data(pil);
- struct tzapp_bg_req bg_tz_req;
- int ret;
- bg_tz_req.tzapp_bg_cmd = BGPIL_IMAGE_LOAD;
- bg_tz_req.address_fw = bg_data->address_fw;
- bg_tz_req.size_fw = bg_data->size_fw;
- ret = bgpil_tzapp_comm(bg_data, &bg_tz_req);
- if (bg_data->cmd_status == BG_CRASH_IN_TWM) {
- /* Do ramdump and resend boot cmd */
- if (is_twm_exit())
- bg_data->subsys_desc.ramdump(true,
- &bg_data->subsys_desc);
- bg_tz_req.tzapp_bg_cmd = BGPIL_DLOAD_CONT;
- ret = bgpil_tzapp_comm(bg_data, &bg_tz_req);
- }
- if (ret || bg_data->cmd_status) {
- dev_err(pil->dev,
- "%s: BGPIL_IMAGE_LOAD qseecom call failed\n",
- __func__);
- pil_free_memory(&bg_data->desc);
- return bg_data->cmd_status;
- }
- /* BG Transfer of image is complete, free up the memory */
- pr_debug("BG Firmware authentication and transfer done\n");
- pil_free_memory(&bg_data->desc);
- return 0;
- }
- /**
- * bg_ramdump() - Called by SSR framework to save dump of BG internal
- * memory, BG PIL does allocate region from dynamic memory and pass this
- * region to tz to dump memory content of BG.
- * @subsys: subsystem descriptor.
- *
- * Return: 0 on success. Error code on failure.
- */
- static int bg_ramdump(int enable, const struct subsys_desc *subsys)
- {
- struct pil_bg_data *bg_data = subsys_to_data(subsys);
- struct pil_desc desc = bg_data->desc;
- struct ramdump_segment *ramdump_segments;
- struct tzapp_bg_req bg_tz_req;
- phys_addr_t start_addr;
- void *region;
- int ret;
- struct device dev = {0};
- arch_setup_dma_ops(&dev, 0, 0, NULL, 0);
- desc.attrs = 0;
- desc.attrs |= DMA_ATTR_SKIP_ZEROING;
- desc.attrs |= DMA_ATTR_STRONGLY_ORDERED;
- region = dma_alloc_attrs(desc.dev, BG_RAMDUMP_SZ,
- &start_addr, GFP_KERNEL, desc.attrs);
- if (region == NULL) {
- dev_dbg(desc.dev,
- "BG PIL failure to allocate ramdump region of size %zx\n",
- BG_RAMDUMP_SZ);
- return -ENOMEM;
- }
- ramdump_segments = kcalloc(1, sizeof(*ramdump_segments), GFP_KERNEL);
- if (!ramdump_segments)
- return -ENOMEM;
- bg_tz_req.tzapp_bg_cmd = BGPIL_RAMDUMP;
- bg_tz_req.address_fw = start_addr;
- bg_tz_req.size_fw = BG_RAMDUMP_SZ;
- ret = bgpil_tzapp_comm(bg_data, &bg_tz_req);
- if (ret || bg_data->cmd_status) {
- dev_dbg(desc.dev, "%s: BG PIL ramdump collection failed\n",
- __func__);
- return bg_data->cmd_status;
- }
- ramdump_segments->address = start_addr;
- ramdump_segments->size = BG_RAMDUMP_SZ;
- do_ramdump(bg_data->ramdump_dev, ramdump_segments, 1);
- kfree(ramdump_segments);
- dma_free_attrs(desc.dev, BG_RAMDUMP_SZ, region,
- start_addr, desc.attrs);
- return 0;
- }
- static struct pil_reset_ops pil_ops_trusted = {
- .init_image = bg_auth_metadata,
- .mem_setup = bg_get_firmware_addr,
- .auth_and_reset = bg_auth_and_xfer,
- .shutdown = NULL,
- .proxy_vote = NULL,
- .proxy_unvote = NULL,
- };
- /**
- * bg_restart_work() - scheduled by interrupt handler to carry
- * out ssr sequence
- * @work: work struct.
- *
- * Return: none.
- */
- static void bg_restart_work(struct work_struct *work)
- {
- struct pil_bg_data *drvdata =
- container_of(work, struct pil_bg_data, restart_work);
- subsystem_restart_dev(drvdata->subsys);
- }
- static irqreturn_t bg_errfatal(int irq, void *dev_id)
- {
- struct pil_bg_data *drvdata = (struct pil_bg_data *)dev_id;
- if (!drvdata)
- return IRQ_HANDLED;
- dev_dbg(drvdata->desc.dev, "BG s/w err fatal\n");
- queue_work(drvdata->bg_queue, &drvdata->restart_work);
- return IRQ_HANDLED;
- }
- static irqreturn_t bg_status_change(int irq, void *dev_id)
- {
- bool value;
- struct pil_bg_data *drvdata = (struct pil_bg_data *)dev_id;
- if (!drvdata)
- return IRQ_HANDLED;
- value = gpio_get_value(drvdata->gpios[0]);
- if (value == true && !drvdata->is_ready) {
- dev_info(drvdata->desc.dev,
- "BG services are up and running: irq state changed 0->1\n");
- drvdata->is_ready = true;
- complete(&drvdata->err_ready);
- } else if (value == false && drvdata->is_ready) {
- dev_err(drvdata->desc.dev,
- "BG got unexpected reset: irq state changed 1->0\n");
- queue_work(drvdata->bg_queue, &drvdata->restart_work);
- } else {
- dev_err(drvdata->desc.dev,
- "BG status irq: unknown status\n");
- }
- return IRQ_HANDLED;
- }
- /**
- * setup_bg_gpio_irq() - called in probe to configure input/
- * output gpio.
- * @drvdata: private data struct for BG.
- *
- * Return: 0 on success. Error code on failure.
- */
- static int setup_bg_gpio_irq(struct platform_device *pdev,
- struct pil_bg_data *drvdata)
- {
- int ret = -1;
- int irq, i;
- if (gpio_request(drvdata->gpios[0], "BG2AP_STATUS")) {
- dev_err(&pdev->dev,
- "%s Failed to configure BG2AP_STATUS gpio\n",
- __func__);
- goto err;
- }
- if (gpio_request(drvdata->gpios[1], "BG2AP_ERRFATAL")) {
- dev_err(&pdev->dev,
- "%s Failed to configure BG2AP_ERRFATAL gpio\n",
- __func__);
- goto err;
- }
- gpio_direction_input(drvdata->gpios[0]);
- gpio_direction_input(drvdata->gpios[1]);
- /* BG2AP STATUS IRQ */
- irq = gpio_to_irq(drvdata->gpios[0]);
- if (irq < 0) {
- dev_err(&pdev->dev,
- "%s: bad BG2AP_STATUS IRQ resource, err = %d\n",
- __func__, irq);
- goto err;
- }
- drvdata->status_irq = irq;
- /* BG2AP ERR_FATAL irq. */
- irq = gpio_to_irq(drvdata->gpios[1]);
- if (irq < 0) {
- dev_err(&pdev->dev, "bad BG2AP_ERRFATAL IRQ resource\n");
- goto err;
- }
- ret = request_irq(irq, bg_errfatal,
- IRQF_TRIGGER_RISING | IRQF_ONESHOT, "bg2ap_errfatal", drvdata);
- if (ret < 0) {
- dev_err(&pdev->dev,
- "%s: BG2AP_ERRFATAL IRQ#%d request failed,\n",
- __func__, irq);
- goto err;
- }
- drvdata->errfatal_irq = irq;
- /* Configure outgoing GPIO's */
- if (gpio_request(drvdata->gpios[2], "AP2BG_ERRFATAL")) {
- dev_err(&pdev->dev,
- "%s Failed to configure AP2BG_ERRFATAL gpio\n",
- __func__);
- goto err;
- }
- if (gpio_request(drvdata->gpios[3], "AP2BG_STATUS")) {
- dev_err(&pdev->dev,
- "%s Failed to configure AP2BG_STATUS gpio\n",
- __func__);
- goto err;
- }
- /*
- * Put status gpio in default high state which will
- * make transition to low on any sudden reset case of msm
- */
- gpio_direction_output(drvdata->gpios[2], 0);
- gpio_direction_output(drvdata->gpios[3], 1);
- /* Inform BG that AP is up */
- gpio_set_value(drvdata->gpios[3], 1);
- return 0;
- err:
- for (i = 0; i < NUM_GPIOS; ++i) {
- if (gpio_is_valid(drvdata->gpios[i]))
- gpio_free(drvdata->gpios[i]);
- }
- return ret;
- }
- /**
- * bg_dt_parse_gpio() - called in probe to parse gpio's
- * @drvdata: private data struct for BG.
- *
- * Return: 0 on success. Error code on failure.
- */
- static int bg_dt_parse_gpio(struct platform_device *pdev,
- struct pil_bg_data *drvdata)
- {
- int i, val;
- for (i = 0; i < NUM_GPIOS; i++)
- drvdata->gpios[i] = INVALID_GPIO;
- val = of_get_named_gpio(pdev->dev.of_node,
- "qcom,bg2ap-status-gpio", 0);
- if (val >= 0)
- drvdata->gpios[0] = val;
- else {
- pr_err("BG status gpio not found, error=%d\n", val);
- return -EINVAL;
- }
- val = of_get_named_gpio(pdev->dev.of_node,
- "qcom,bg2ap-errfatal-gpio", 0);
- if (val >= 0)
- drvdata->gpios[1] = val;
- else {
- pr_err("BG err-fatal gpio not found, error=%d\n", val);
- return -EINVAL;
- }
- val = of_get_named_gpio(pdev->dev.of_node,
- "qcom,ap2bg-errfatal-gpio", 0);
- if (val >= 0)
- drvdata->gpios[2] = val;
- else {
- pr_err("ap2bg err-fatal gpio not found, error=%d\n", val);
- return -EINVAL;
- }
- val = of_get_named_gpio(pdev->dev.of_node,
- "qcom,ap2bg-status-gpio", 0);
- if (val >= 0)
- drvdata->gpios[3] = val;
- else {
- pr_err("ap2bg status gpio not found, error=%d\n", val);
- return -EINVAL;
- }
- return 0;
- }
- static int pil_bg_driver_probe(struct platform_device *pdev)
- {
- struct pil_bg_data *bg_data;
- int rc;
- bg_data = devm_kzalloc(&pdev->dev, sizeof(*bg_data), GFP_KERNEL);
- if (!bg_data)
- return -ENOMEM;
- platform_set_drvdata(pdev, bg_data);
- rc = of_property_read_string(pdev->dev.of_node,
- "qcom,firmware-name", &bg_data->desc.name);
- if (rc)
- return rc;
- bg_data->desc.dev = &pdev->dev;
- bg_data->desc.owner = THIS_MODULE;
- bg_data->desc.ops = &pil_ops_trusted;
- rc = pil_desc_init(&bg_data->desc);
- if (rc)
- return rc;
- /* Read gpio configuration */
- rc = bg_dt_parse_gpio(pdev, bg_data);
- if (rc)
- return rc;
- rc = setup_bg_gpio_irq(pdev, bg_data);
- if (rc < 0)
- return rc;
- bg_data->subsys_desc.name = bg_data->desc.name;
- bg_data->subsys_desc.owner = THIS_MODULE;
- bg_data->subsys_desc.dev = &pdev->dev;
- bg_data->subsys_desc.shutdown = bg_shutdown;
- bg_data->subsys_desc.powerup = bg_powerup;
- bg_data->subsys_desc.ramdump = bg_ramdump;
- bg_data->subsys_desc.free_memory = NULL;
- bg_data->subsys_desc.crash_shutdown = bg_app_shutdown_notify;
- bg_data->ramdump_dev =
- create_ramdump_device(bg_data->subsys_desc.name, &pdev->dev);
- if (!bg_data->ramdump_dev) {
- rc = -ENOMEM;
- goto err_ramdump;
- }
- bg_data->subsys = subsys_register(&bg_data->subsys_desc);
- if (IS_ERR(bg_data->subsys)) {
- rc = PTR_ERR(bg_data->subsys);
- goto err_subsys;
- }
- bg_data->reboot_blk.notifier_call = bg_app_reboot_notify;
- register_reboot_notifier(&bg_data->reboot_blk);
- bg_data->bg_queue = alloc_workqueue("bg_queue", 0, 0);
- if (!bg_data->bg_queue) {
- dev_err(&pdev->dev, "could not create bg_queue\n");
- subsys_unregister(bg_data->subsys);
- goto err_subsys;
- }
- INIT_WORK(&bg_data->restart_work, bg_restart_work);
- return 0;
- err_subsys:
- destroy_ramdump_device(bg_data->ramdump_dev);
- err_ramdump:
- pil_desc_release(&bg_data->desc);
- return rc;
- }
- static int pil_bg_driver_exit(struct platform_device *pdev)
- {
- struct pil_bg_data *bg_data = platform_get_drvdata(pdev);
- subsys_unregister(bg_data->subsys);
- destroy_ramdump_device(bg_data->ramdump_dev);
- pil_desc_release(&bg_data->desc);
- return 0;
- }
- const struct of_device_id pil_bg_match_table[] = {
- {.compatible = "qcom,pil-blackghost"},
- {}
- };
- static struct platform_driver pil_bg_driver = {
- .probe = pil_bg_driver_probe,
- .remove = pil_bg_driver_exit,
- .driver = {
- .name = "subsys-pil-bg",
- .of_match_table = pil_bg_match_table,
- .owner = THIS_MODULE,
- },
- };
- static int __init pil_bg_init(void)
- {
- return platform_driver_register(&pil_bg_driver);
- }
- module_init(pil_bg_init);
- static void __exit pil_bg_exit(void)
- {
- platform_driver_unregister(&pil_bg_driver);
- }
- module_exit(pil_bg_exit);
- MODULE_DESCRIPTION("Support for booting QTI Blackghost SoC");
- MODULE_LICENSE("GPL v2");
|