--- zzzz-none-000/linux-5.15.111/drivers/bus/mhi/core/boot.c 2023-05-11 14:00:40.000000000 +0000 +++ puma7-atom-6670-761/linux-5.15.111/drivers/bus/mhi/core/boot.c 2024-02-07 10:22:37.000000000 +0000 @@ -13,11 +13,20 @@ #include #include #include +#include +#include #include #include #include #include "internal.h" +#define PCIE_PCIE_LOCAL_REG_PCIE_LOCAL_RSV1 0x3168 +#define PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0 0x4040 +#define PCIE_REMAP_BAR_CTRL_OFFSET 0x310C +#define PCIE_SCRATCH_0_WINDOW_VAL 0x4000003C +#define MAX_UNWINDOWED_ADDRESS 0x80000 +#define PCIE_REG_FOR_BOOT_ARGS PCIE_SOC_PCIE_REG_PCIE_SCRATCH_0 + /* Setup RDDM vector table for RDDM transfer and program RXVEC */ void mhi_rddm_prepare(struct mhi_controller *mhi_cntrl, struct image_info *img_info) @@ -386,6 +395,186 @@ } } +static void *mhi_download_fw_license_or_secdat(struct mhi_controller *mhi_cntrl) +{ + struct device *dev = &mhi_cntrl->mhi_dev->dev; + int ret; + void *buf; + const struct firmware *file = NULL; + size_t header_size; + const char *filename = NULL; + char *magic = NULL; + + /* Check the ftm-mode or license-file is defined in device tree */ + if (of_property_read_bool(mhi_cntrl->cntrl_dev->of_node, "ftm-mode")) { + if (of_property_read_string(mhi_cntrl->cntrl_dev->of_node, + "secdat-file", &filename) == 0) { + if (filename != NULL && (strlen(filename) != 0)) + magic = "SBSD"; + } + } else if (of_property_read_string(mhi_cntrl->cntrl_dev->of_node, + "license-file", &filename) == 0 ) { + if (filename != NULL && (strlen(filename) != 0)) + magic = "SSLD"; + } else { + dev_err(dev, "License file or ftm-mode not present in DTS node," + "Assuming no License or ftm mode\n"); + mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, + PCIE_PCIE_LOCAL_REG_PCIE_LOCAL_RSV1, (u32)0x0); + return NULL; + } + + if (filename == NULL || magic == NULL) { + dev_err(dev, "License or secdat file is empty in DTS node," + "Assuming no License or ftm mode\n"); + mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, + PCIE_PCIE_LOCAL_REG_PCIE_LOCAL_RSV1, (u32)0x0); + return NULL; + + } + + /* + * Load the file from file system into DMA memory. + * Format is + * <4 Byte Magic><4 Byte Length if file Payload> + */ + ret = request_firmware(&file, filename, dev); + if (ret) { + dev_err(dev, "Error in loading file (%s) : %d," + " Assuming no license or ftm mode\n", filename, ret); + mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, + PCIE_PCIE_LOCAL_REG_PCIE_LOCAL_RSV1, (u32)0x0); + return NULL; + } + + header_size = 4 + 4; /* size of magic, size of length */ + buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, + file->size + header_size, + &mhi_cntrl->license_dma_addr, GFP_KERNEL); + if (!buf) { + release_firmware(file); + dev_err(dev, "Error Allocating memory for license or ftm mode : %d\n", ret); + return NULL; + } + + /* setup the buffer: magic, length, payload */ +#define DATA_MAGIC_SIZE 4 + + memcpy(buf, magic, DATA_MAGIC_SIZE); + + memcpy(buf + DATA_MAGIC_SIZE, (void *)&file->size, sizeof(file->size)); + + memcpy(buf + header_size, file->data, file->size); + + mhi_cntrl->license_buf_size = file->size + header_size; + + /* Let device know the license or secdat data address : Assuming 32 bit only*/ + mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, PCIE_PCIE_LOCAL_REG_PCIE_LOCAL_RSV1, + lower_32_bits(mhi_cntrl->license_dma_addr)); + + release_firmware(file); + + dev_info(dev, "License or secdat file address copied to PCIE_PCIE_LOCAL_REG_PCIE_LOCAL_RSV1\n"); + + return buf; +} + +void mhi_free_fw_license_or_secdat(struct mhi_controller *mhi_cntrl) +{ + if (mhi_cntrl->license_buf != NULL) { + dma_free_coherent(mhi_cntrl->cntrl_dev, mhi_cntrl->license_buf_size, + mhi_cntrl->license_buf, mhi_cntrl->license_dma_addr); + mhi_cntrl->license_buf = NULL; + } +} + +static int mhi_update_scratch_reg(struct mhi_controller *mhi_cntrl, u32 val) +{ + struct device *dev = &mhi_cntrl->mhi_dev->dev; + u32 rd_val; + int ret; + + /* Program Window register to update boot args pointer */ + ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs, PCIE_REMAP_BAR_CTRL_OFFSET, + &rd_val); + if (ret) + return ret; + + rd_val = rd_val & ~(0x3f); + + mhi_write_reg(mhi_cntrl, mhi_cntrl->regs, PCIE_REMAP_BAR_CTRL_OFFSET, + PCIE_SCRATCH_0_WINDOW_VAL); + + mhi_write_reg(mhi_cntrl, mhi_cntrl->regs + MAX_UNWINDOWED_ADDRESS, + PCIE_REG_FOR_BOOT_ARGS, val); + + ret = mhi_read_reg(mhi_cntrl, mhi_cntrl->regs + MAX_UNWINDOWED_ADDRESS, + PCIE_REG_FOR_BOOT_ARGS, &rd_val); + if (ret) + return ret; + + if (rd_val != val) { + dev_err(dev, "Write to PCIE_REG_FOR_BOOT_ARGS register failed\n"); + return -EFAULT; + } + + return 0; +} + +static int mhi_handle_boot_args(struct mhi_controller *mhi_cntrl) +{ + struct device *dev = &mhi_cntrl->mhi_dev->dev; + int i, cnt, ret; + u32 val; + + if (!mhi_cntrl->cntrl_dev->of_node) + return -EINVAL; + + cnt = of_property_count_u32_elems(mhi_cntrl->cntrl_dev->of_node, + "boot-args"); + if (cnt < 0) { + dev_err(dev, "boot-args not defined in DTS. ret:%d\n", cnt); + mhi_update_scratch_reg(mhi_cntrl, 0); + return 0; + } + + mhi_cntrl->bootargs_buf = dma_alloc_coherent(mhi_cntrl->cntrl_dev, PAGE_SIZE, + &mhi_cntrl->bootargs_dma, GFP_KERNEL); + + if (!mhi_cntrl->bootargs_buf) { + mhi_update_scratch_reg(mhi_cntrl, 0); + return -ENOMEM; + } + + for (i = 0; i < cnt; i++) { + ret = of_property_read_u32_index(mhi_cntrl->cntrl_dev->of_node, + "boot-args", i, &val); + if (ret) { + dev_err(dev, "failed to read boot args\n"); + dma_free_coherent(mhi_cntrl->cntrl_dev, PAGE_SIZE, mhi_cntrl->bootargs_buf, + mhi_cntrl->bootargs_dma); + mhi_cntrl->bootargs_buf = NULL; + mhi_update_scratch_reg(mhi_cntrl, 0); + return ret; + } + mhi_cntrl->bootargs_buf[i] = (u8)val; + } + + ret = mhi_update_scratch_reg(mhi_cntrl, lower_32_bits(mhi_cntrl->bootargs_dma)); + + dev_dbg(dev, "boot-args address copied to PCIE_REG_FOR_BOOT_ARGS\n"); + + return ret; +} + +void mhi_free_boot_args(struct mhi_controller *mhi_cntrl) +{ + if (mhi_cntrl->bootargs_buf != NULL) { + dma_free_coherent(mhi_cntrl->cntrl_dev, PAGE_SIZE, mhi_cntrl->bootargs_buf, mhi_cntrl->bootargs_dma); + mhi_cntrl->bootargs_buf = NULL; + } +} + void mhi_fw_load_handler(struct mhi_controller *mhi_cntrl) { const struct firmware *firmware = NULL; @@ -515,11 +704,23 @@ { struct image_info *image_info = mhi_cntrl->fbc_image; struct device *dev = &mhi_cntrl->mhi_dev->dev; + struct pci_dev *pdev = to_pci_dev(mhi_cntrl->cntrl_dev); int ret; if (!image_info) return -EIO; + ret = mhi_handle_boot_args(mhi_cntrl); + if(ret) { + dev_err(dev, "Failed to handle the boot-args, ret: %d\n",ret); + return ret; + } + + if (pdev && pdev->device == QCN9224_DEVICE_ID) { + /* Download the License */ + mhi_cntrl->license_buf = mhi_download_fw_license_or_secdat(mhi_cntrl); + } + ret = mhi_fw_load_bhie(mhi_cntrl, /* Vector table is the last entry */ &image_info->mhi_buf[image_info->entries - 1]);