blob: 22435406b574ca2f143e7a9f4e040ee2580a447e [file] [log] [blame]
// SPDX-License-Identifier: GPL-2.0-only
/* Copyright (c) 2012-2016, 2018-2020, 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/module.h>
#include <linux/pm_qos.h>
#include <linux/clk.h>
#include <linux/io.h>
#include <linux/clk/qcom.h>
#include <linux/msm-bus.h>
#include <linux/msm-bus-board.h>
#include <linux/iommu.h>
#include <asm/dma-iommu.h>
#include <linux/dma-direction.h>
#include <linux/dma-buf.h>
#include "msm_camera_io_util.h"
#include "msm_jpeg_platform.h"
#include "msm_jpeg_sync.h"
#include "msm_jpeg_common.h"
#include "msm_jpeg_hw.h"
#define JPEG_DT_PROP_CNT 2
static int msm_jpeg_get_clock_index(struct msm_jpeg_device *pgmn_dev,
const char *clk_name)
{
uint32_t i = 0;
for (i = 0; i < pgmn_dev->num_clk; i++) {
if (!strcmp(clk_name, pgmn_dev->jpeg_clk_info[i].clk_name))
return i;
}
return -EINVAL;
}
int msm_jpeg_platform_set_clk_rate(struct msm_jpeg_device *pgmn_dev,
long clk_rate)
{
int rc = 0;
int msm_jpeg_idx;
/* retrieve clock index from list of clocks */
msm_jpeg_idx = msm_jpeg_get_clock_index(pgmn_dev,
"core_clk");
if (msm_jpeg_idx < 0) {
JPEG_PR_ERR("%s:Fail to get clock index\n", __func__);
return -EINVAL;
}
/* set the rate */
msm_camera_clk_set_rate(&pgmn_dev->pdev->dev,
pgmn_dev->jpeg_clk[msm_jpeg_idx], clk_rate);
return rc;
}
void msm_jpeg_platform_p2v(int iommu_hdl, int fd)
{
cam_smmu_put_phy_addr(iommu_hdl, fd);
}
uint32_t msm_jpeg_platform_v2p(struct msm_jpeg_device *pgmn_dev, int fd,
uint32_t len, int iommu_hdl)
{
dma_addr_t paddr;
size_t size;
int rc;
rc = cam_smmu_get_phy_addr(pgmn_dev->iommu_hdl, fd, CAM_SMMU_MAP_RW,
&paddr, &size);
JPEG_DBG("%s:%d] addr 0x%x size %zu", __func__, __LINE__,
(uint32_t)paddr, size);
if (rc < 0) {
JPEG_PR_ERR("%s: fd %d got phy addr error %d\n", __func__, fd,
rc);
goto err_get_phy;
}
/* validate user input */
if (len > size) {
JPEG_PR_ERR("%s: invalid offset + len\n", __func__);
goto err_size;
}
return paddr;
err_size:
cam_smmu_put_phy_addr(pgmn_dev->iommu_hdl, fd);
err_get_phy:
return 0;
}
static void set_vbif_params(struct msm_jpeg_device *pgmn_dev,
void *jpeg_vbif_base)
{
msm_camera_io_w(0x1,
(void __iomem *)(jpeg_vbif_base + JPEG_VBIF_CLKON));
if (pgmn_dev->hw_version != JPEG_8994) {
msm_camera_io_w(0x10101010,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_IN_RD_LIM_CONF0));
msm_camera_io_w(0x10101010,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_IN_RD_LIM_CONF1));
msm_camera_io_w(0x10101010,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_IN_RD_LIM_CONF2));
msm_camera_io_w(0x10101010,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_IN_WR_LIM_CONF0));
msm_camera_io_w(0x10101010,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_IN_WR_LIM_CONF1));
msm_camera_io_w(0x10101010,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_IN_WR_LIM_CONF2));
msm_camera_io_w(0x00001010,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_OUT_RD_LIM_CONF0));
msm_camera_io_w(0x00000110,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_OUT_WR_LIM_CONF0));
msm_camera_io_w(0x00000707,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_DDR_OUT_MAX_BURST));
msm_camera_io_w(0x00000FFF,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_OUT_AXI_AOOO_EN));
msm_camera_io_w(0x0FFF0FFF,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_OUT_AXI_AOOO));
msm_camera_io_w(0x2222,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF1));
}
msm_camera_io_w(0x7,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_OCMEM_OUT_MAX_BURST));
msm_camera_io_w(0x00000030,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_ARB_CTL));
/* FE and WE QOS configuration need to be set when
* QOS RR arbitration is enabled
*/
if (pgmn_dev->hw_version != JPEG_8974_V1)
msm_camera_io_w(0x00000003,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_ROUND_ROBIN_QOS_ARB));
else
msm_camera_io_w(0x00000001,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_ROUND_ROBIN_QOS_ARB));
msm_camera_io_w(0x22222222,
(void __iomem *)(jpeg_vbif_base +
JPEG_VBIF_OUT_AXI_AMEMTYPE_CONF0));
}
/*
* msm_jpeg_set_init_dt_parms() - get device tree config and write to registers.
* @pgmn_dev: Pointer to jpeg device.
* @dt_prop_name: Device tree property name.
* @base: Base address.
*
* This function reads register offsets and values from dtsi based on
* device tree property name and writes to jpeg registers.
*
* Return: 0 on success and negative error on failure.
*/
static int32_t msm_jpeg_set_init_dt_parms(struct msm_jpeg_device *pgmn_dev,
const char *dt_prop_name,
void *base)
{
struct device_node *of_node;
int32_t i = 0, rc = 0;
uint32_t *dt_reg_settings = NULL;
uint32_t dt_count = 0;
of_node = pgmn_dev->pdev->dev.of_node;
JPEG_DBG("%s:%d E\n", __func__, __LINE__);
if (!of_get_property(of_node, dt_prop_name,
&dt_count)) {
JPEG_DBG("%s: Error property does not exist\n",
__func__);
return -ENOENT;
}
if (dt_count % 8) {
JPEG_PR_ERR("%s: Error invalid entries\n",
__func__);
return -EINVAL;
}
dt_count /= 4;
if (dt_count != 0) {
dt_reg_settings = kcalloc(dt_count, sizeof(uint32_t),
GFP_KERNEL);
if (!dt_reg_settings) {
JPEG_PR_ERR("%s:%d No memory\n",
__func__, __LINE__);
return -ENOMEM;
}
rc = of_property_read_u32_array(of_node,
dt_prop_name,
dt_reg_settings,
dt_count);
if (rc < 0) {
JPEG_PR_ERR("%s: No reg info\n",
__func__);
kfree(dt_reg_settings);
return -EINVAL;
}
for (i = 0; i < dt_count; i = i + 2) {
JPEG_DBG("%s:%d] %pK %08x\n",
__func__, __LINE__,
base + dt_reg_settings[i],
dt_reg_settings[i + 1]);
msm_camera_io_w(dt_reg_settings[i + 1],
(void __iomem *)
(base + dt_reg_settings[i]));
}
kfree(dt_reg_settings);
}
return 0;
}
static int msm_jpeg_attach_iommu(struct msm_jpeg_device *pgmn_dev)
{
int rc;
rc = cam_smmu_ops(pgmn_dev->iommu_hdl, CAM_SMMU_ATTACH);
if (rc < 0) {
JPEG_PR_ERR("%s: Device attach failed\n", __func__);
return -ENODEV;
}
JPEG_DBG("%s:%d] handle %d attach\n",
__func__, __LINE__, pgmn_dev->iommu_hdl);
return 0;
}
static int msm_jpeg_detach_iommu(struct msm_jpeg_device *pgmn_dev)
{
JPEG_DBG("%s:%d] handle %d detach\n",
__func__, __LINE__, pgmn_dev->iommu_hdl);
cam_smmu_ops(pgmn_dev->iommu_hdl, CAM_SMMU_DETACH);
return 0;
}
int msm_jpeg_platform_init(irqreturn_t (*handler)(int, void *),
void *context)
{
int rc = -1;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *) context;
struct platform_device *pdev = pgmn_dev->pdev;
pgmn_dev->state = MSM_JPEG_IDLE;
/* enable all regulators */
rc = msm_camera_regulator_enable(pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg, true);
if (rc < 0) {
JPEG_PR_ERR("%s: failed to enable regulators\n", __func__);
goto err_reg_enable;
}
/* enable all clocks */
rc = msm_camera_clk_enable(&pgmn_dev->pdev->dev,
pgmn_dev->jpeg_clk_info, pgmn_dev->jpeg_clk,
pgmn_dev->num_clk, true);
if (rc < 0) {
JPEG_PR_ERR("%s: clk enable failed\n", __func__);
goto err_clk_enable;
}
/* attach the smmu context banks */
rc = msm_jpeg_attach_iommu(pgmn_dev);
if (rc < 0) {
JPEG_PR_ERR("%s: iommu attach failed\n", __func__);
goto err_fail_iommu;
}
rc = msm_jpeg_set_init_dt_parms(pgmn_dev, "qcom,vbif-reg-settings",
pgmn_dev->vbif_base);
if (rc == -ENOENT) {
JPEG_DBG("%s: No qcom,vbif-reg-settings property\n", __func__);
set_vbif_params(pgmn_dev, pgmn_dev->vbif_base);
} else if (rc < 0) {
JPEG_PR_ERR("%s: vbif params set fail\n", __func__);
goto err_fail_set_vbif;
}
/* register the interrupt handler */
rc = msm_camera_register_irq(pgmn_dev->pdev,
pgmn_dev->jpeg_irq_res, handler, IRQF_TRIGGER_RISING,
"jpeg", context);
if (rc < 0) {
JPEG_PR_ERR("%s: irq request fail\n", __func__);
goto err_reg_irq_fail;
}
pgmn_dev->hw_version = msm_camera_io_r((void __iomem *)(pgmn_dev->base +
JPEG_HW_VERSION));
JPEG_DBG_HIGH("%s:%d] jpeg HW version 0x%x", __func__, __LINE__,
pgmn_dev->hw_version);
pgmn_dev->state = MSM_JPEG_INIT;
rc = msm_jpeg_set_init_dt_parms(pgmn_dev, "qcom,vbif-qos-setting",
pgmn_dev->vbif_base);
if (rc == -ENOENT)
JPEG_DBG("%s: No qcom,vbif-qos-setting property\n", __func__);
else if (rc < 0) {
JPEG_PR_ERR("%s: vbif qos params set fail\n", __func__);
goto err_reg_enable;
}
return 0;
err_reg_irq_fail:
err_fail_set_vbif:
msm_jpeg_detach_iommu(pgmn_dev);
err_fail_iommu:
msm_camera_clk_enable(&pdev->dev, pgmn_dev->jpeg_clk_info,
pgmn_dev->jpeg_clk, pgmn_dev->num_clk, false);
err_clk_enable:
msm_camera_regulator_enable(pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg, false);
err_reg_enable:
return rc;
}
int msm_jpeg_platform_setup(struct msm_jpeg_device *pgmn_dev)
{
int rc = -1;
int i;
struct resource *jpeg_irq_res;
void __iomem *jpeg_base, *vbif_base;
struct platform_device *pdev = pgmn_dev->pdev;
/* get the jpeg hardware device address */
jpeg_base = msm_camera_get_reg_base(pdev, "jpeg_hw", true);
if (!jpeg_base) {
JPEG_PR_ERR("%s: jpeg no mem resource?\n", __func__);
rc = -ENXIO;
goto out;
}
/* get the jpeg vbif device address */
vbif_base = msm_camera_get_reg_base(pdev, "jpeg_vbif", false);
if (!vbif_base) {
JPEG_PR_ERR("%s: vbif no mem resource?\n", __func__);
rc = -ENXIO;
goto err_vbif_base;
}
/* get the irq resource for the jpeg hardware */
jpeg_irq_res = msm_camera_get_irq(pdev, "jpeg");
if (!jpeg_irq_res) {
JPEG_PR_ERR("%s: no irq resource?\n", __func__);
rc = -ENXIO;
goto err_jpeg_irq_res;
}
/* get all the clocks information */
rc = msm_camera_get_clk_info(pdev, &pgmn_dev->jpeg_clk_info,
&pgmn_dev->jpeg_clk, &pgmn_dev->num_clk);
if (rc < 0) {
JPEG_PR_ERR("%s: failed to get the clocks\n", __func__);
rc = -ENXIO;
goto err_jpeg_clk;
}
/*set memcore and mem periphery logic flags to 0*/
for (i = 0; i < pgmn_dev->num_clk; i++) {
if ((strcmp(pgmn_dev->jpeg_clk_info[i].clk_name,
"core_clk") == 0) ||
(strcmp(pgmn_dev->jpeg_clk_info[i].clk_name,
"mmss_camss_jpeg_axi_clk") == 0)) {
msm_camera_set_clk_flags(pgmn_dev->jpeg_clk[i],
CLKFLAG_NORETAIN_MEM);
msm_camera_set_clk_flags(pgmn_dev->jpeg_clk[i],
CLKFLAG_NORETAIN_PERIPH);
}
}
/* get all the regulators information */
rc = msm_camera_get_regulator_info(pdev, &pgmn_dev->jpeg_vdd,
&pgmn_dev->num_reg);
if (rc < 0) {
JPEG_PR_ERR("%s: failed to get the regulators\n", __func__);
rc = -ENXIO;
goto err_jpeg_get_reg;
}
/* map the dtsi cell id to bus client id */
switch (pgmn_dev->pdev->id) {
case 0:
pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_ENC0;
break;
case 1:
pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_ENC1;
break;
case 2:
pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_DEC;
break;
case 3:
pgmn_dev->bus_client = CAM_BUS_CLIENT_JPEG_DMA;
break;
default:
JPEG_PR_ERR("%s: invalid cell id :%d\n",
__func__, pgmn_dev->pdev->id);
goto err_jpeg_get_reg;
}
/* register the bus client */
rc = msm_camera_register_bus_client(pgmn_dev->pdev,
pgmn_dev->bus_client);
if (rc < 0) {
JPEG_PR_ERR("Fail to register bus client\n");
rc = -EINVAL;
goto err_reg_bus;
}
/* get the resource size of jpeg hardware */
pgmn_dev->res_size = msm_camera_get_res_size(pdev, "jpeg_hw");
if (!pgmn_dev->res_size) {
JPEG_PR_ERR("Fail to resource size\n");
rc = -EINVAL;
goto err_res_size;
}
pgmn_dev->base = (void *)jpeg_base;
pgmn_dev->vbif_base = (void *)vbif_base;
pgmn_dev->jpeg_irq_res = jpeg_irq_res;
return 0;
err_res_size:
msm_camera_unregister_bus_client(pgmn_dev->bus_client);
err_reg_bus:
msm_camera_put_regulators(pdev, &pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg);
err_jpeg_get_reg:
msm_camera_put_clk_info(pdev, &pgmn_dev->jpeg_clk_info,
&pgmn_dev->jpeg_clk, pgmn_dev->num_clk);
err_jpeg_clk:
err_jpeg_irq_res:
msm_camera_put_reg_base(pdev, vbif_base, "jpeg_vbif", false);
err_vbif_base:
msm_camera_put_reg_base(pdev, jpeg_base, "jpeg_hw", true);
out:
return rc;
}
void msm_jpeg_platform_cleanup(struct msm_jpeg_device *pgmn_dev)
{
/* unregister the bus client */
msm_camera_unregister_bus_client(pgmn_dev->bus_client);
/* release the regulators */
msm_camera_put_regulators(pgmn_dev->pdev, &pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg);
/* release all the clocks */
msm_camera_put_clk_info(pgmn_dev->pdev, &pgmn_dev->jpeg_clk_info,
&pgmn_dev->jpeg_clk, pgmn_dev->num_clk);
/* release the jpeg device memory */
msm_camera_put_reg_base(pgmn_dev->pdev,
(void __iomem *)pgmn_dev->vbif_base,
"jpeg_vbif", false);
/* release the jpeg vbif device memory */
msm_camera_put_reg_base(pgmn_dev->pdev,
(void __iomem *)pgmn_dev->base,
"jpeg_hw", true);
}
int msm_jpeg_platform_release(void *context)
{
int result = 0;
struct msm_jpeg_device *pgmn_dev =
(struct msm_jpeg_device *) context;
/* release the irq */
msm_camera_unregister_irq(pgmn_dev->pdev,
pgmn_dev->jpeg_irq_res, context);
msm_jpeg_detach_iommu(pgmn_dev);
if (pgmn_dev->bus_client) {
if (pgmn_dev->jpeg_bus_vote) {
/* update the bw with zeroth vector */
msm_camera_update_bus_vector(pgmn_dev->bus_client, 0);
JPEG_BUS_UNVOTED(pgmn_dev);
JPEG_DBG("%s:%d] Bus unvoted\n", __func__, __LINE__);
}
}
/* disable all the clocks */
msm_camera_clk_enable(&pgmn_dev->pdev->dev, pgmn_dev->jpeg_clk_info,
pgmn_dev->jpeg_clk, pgmn_dev->num_clk, false);
JPEG_DBG("%s:%d] clock disable done", __func__, __LINE__);
/* disable all the regulators */
msm_camera_regulator_enable(pgmn_dev->jpeg_vdd,
pgmn_dev->num_reg, false);
JPEG_DBG("%s:%d] regulator disable done", __func__, __LINE__);
pgmn_dev->state = MSM_JPEG_IDLE;
JPEG_DBG("%s:%d] success\n", __func__, __LINE__);
return result;
}
/*
* msm_jpeg_platform_set_dt_config() - set jpeg device tree configuration.
* @pgmn_dev: Pointer to jpeg device.
*
* This function holds an array of device tree property names and calls
* msm_jpeg_set_init_dt_parms() for each property.
*
* Return: 0 on success and negative error on failure.
*/
int msm_jpeg_platform_set_dt_config(struct msm_jpeg_device *pgmn_dev)
{
int rc = 0;
uint8_t dt_prop_cnt = JPEG_DT_PROP_CNT;
char *dt_prop_name[JPEG_DT_PROP_CNT] = {"qcom,qos-reg-settings",
"qcom,prefetch-reg-settings"};
while (dt_prop_cnt) {
dt_prop_cnt--;
rc = msm_jpeg_set_init_dt_parms(pgmn_dev,
dt_prop_name[dt_prop_cnt],
pgmn_dev->base);
if (rc == -ENOENT) {
JPEG_DBG("%s: No %s property\n", __func__,
dt_prop_name[dt_prop_cnt]);
} else if (rc < 0) {
JPEG_PR_ERR("%s: %s params set fail\n", __func__,
dt_prop_name[dt_prop_cnt]);
return rc;
}
}
return rc;
}