mirror of
https://github.com/torvalds/linux.git
synced 2026-06-08 14:42:37 +02:00
video: rockchip: vpu: transplant power ops from kernel 3.10
Change-Id: I7aa29819ab33d5ce676751fe74edec947d5cc895 Signed-off-by: Jung Zhao <jung.zhao@rock-chips.com>
This commit is contained in:
parent
b359b5f287
commit
e2c56b719b
|
|
@ -182,27 +182,6 @@ static const struct vcodec_info vcodec_info_set[] = {
|
|||
},
|
||||
};
|
||||
|
||||
/* Both VPU1 and VPU2 */
|
||||
static const struct vcodec_device_info vpu_device_info = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_VPUX,
|
||||
.name = "vpu-service",
|
||||
};
|
||||
|
||||
static const struct vcodec_device_info vpu_combo_device_info = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_VPUC,
|
||||
.name = "vpu-combo",
|
||||
};
|
||||
|
||||
static const struct vcodec_device_info hevc_device_info = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_HEVC,
|
||||
.name = "hevc-service",
|
||||
};
|
||||
|
||||
static const struct vcodec_device_info rkvd_device_info = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_RKVD,
|
||||
.name = "rkvdec",
|
||||
};
|
||||
|
||||
#define DEBUG
|
||||
#ifdef DEBUG
|
||||
#define vpu_debug_func(type, fmt, args...) \
|
||||
|
|
@ -360,6 +339,10 @@ struct vpu_service_info {
|
|||
struct clk *clk_cabac;
|
||||
struct clk *pd_video;
|
||||
|
||||
unsigned long aclk_vcodec_default_rate;
|
||||
unsigned long clk_core_default_rate;
|
||||
unsigned long clk_cabac_default_rate;
|
||||
|
||||
#ifdef CONFIG_RESET_CONTROLLER
|
||||
struct reset_control *rst_a;
|
||||
struct reset_control *rst_h;
|
||||
|
|
@ -394,6 +377,27 @@ struct vpu_service_info {
|
|||
struct list_head subdev_list;
|
||||
|
||||
u32 alloc_type;
|
||||
|
||||
struct vcodec_hw_ops *hw_ops;
|
||||
const struct vcodec_hw_var *hw_var;
|
||||
};
|
||||
|
||||
struct vcodec_hw_ops {
|
||||
void (*power_on)(struct vpu_service_info *pservice);
|
||||
void (*power_off)(struct vpu_service_info *pservice);
|
||||
void (*get_freq)(struct vpu_subdev_data *data, struct vpu_reg *reg);
|
||||
void (*set_freq)(struct vpu_service_info *pservice,
|
||||
struct vpu_reg *reg);
|
||||
void (*reduce_freq)(struct vpu_service_info *pservice);
|
||||
};
|
||||
|
||||
struct vcodec_hw_var {
|
||||
s32 device_type;
|
||||
u8 *name;
|
||||
enum pmu_idle_req pmu_type;
|
||||
struct vcodec_hw_ops *ops;
|
||||
int (*init)(struct vpu_service_info *pservice);
|
||||
void (*config)(struct vpu_subdev_data *data);
|
||||
};
|
||||
|
||||
#ifdef CONFIG_COMPAT
|
||||
|
|
@ -558,21 +562,26 @@ static int vpu_get_clk(struct vpu_service_info *pservice)
|
|||
if (IS_ERR(pservice->clk_cabac)) {
|
||||
dev_err(dev, "failed on clk_get clk_cabac\n");
|
||||
pservice->clk_cabac = NULL;
|
||||
} else {
|
||||
pservice->clk_cabac_default_rate =
|
||||
clk_get_rate(pservice->clk_cabac);
|
||||
}
|
||||
pservice->clk_core = devm_clk_get(dev, "clk_core");
|
||||
if (IS_ERR(pservice->clk_core)) {
|
||||
dev_err(dev, "failed on clk_get clk_core\n");
|
||||
pservice->clk_core = NULL;
|
||||
/* The VDPU and AVSD combo doesn't need those clocks */
|
||||
if (pservice->dev_id == VCODEC_DEVICE_ID_RKVDEC)
|
||||
return -1;
|
||||
return -1;
|
||||
} else {
|
||||
pservice->clk_core_default_rate =
|
||||
clk_get_rate(pservice->clk_core);
|
||||
}
|
||||
case VCODEC_DEVICE_ID_VPU:
|
||||
pservice->aclk_vcodec = devm_clk_get(dev, "aclk_vcodec");
|
||||
if (IS_ERR(pservice->aclk_vcodec)) {
|
||||
dev_err(dev, "failed on clk_get aclk_vcodec\n");
|
||||
pservice->aclk_vcodec = NULL;
|
||||
return -1;
|
||||
} else {
|
||||
pservice->aclk_vcodec_default_rate =
|
||||
clk_get_rate(pservice->aclk_vcodec);
|
||||
}
|
||||
|
||||
pservice->hclk_vcodec = devm_clk_get(dev, "hclk_vcodec");
|
||||
|
|
@ -602,7 +611,6 @@ static int vpu_get_clk(struct vpu_service_info *pservice)
|
|||
static void _vpu_reset(struct vpu_subdev_data *data)
|
||||
{
|
||||
struct vpu_service_info *pservice = data->pservice;
|
||||
unsigned long rate = 0;
|
||||
|
||||
dev_info(pservice->dev, "resetting...\n");
|
||||
WARN_ON(pservice->reg_codec != NULL);
|
||||
|
|
@ -614,13 +622,8 @@ static void _vpu_reset(struct vpu_subdev_data *data)
|
|||
|
||||
#ifdef CONFIG_RESET_CONTROLLER
|
||||
rockchip_pmu_idle_request(pservice->dev, true);
|
||||
rate = clk_get_rate(pservice->aclk_vcodec);
|
||||
/*
|
||||
* Some old platforms can't run at 300MHZ, they don't request
|
||||
* decrease the frequency at resetting either. It is safe to
|
||||
* keep here in 200 MHZ.
|
||||
*/
|
||||
clk_set_rate(pservice->aclk_vcodec, 200 * MHZ);
|
||||
if (pservice->hw_ops->reduce_freq)
|
||||
pservice->hw_ops->reduce_freq(pservice);
|
||||
|
||||
try_reset_assert(pservice->rst_niu_a);
|
||||
try_reset_assert(pservice->rst_niu_h);
|
||||
|
|
@ -640,11 +643,15 @@ static void _vpu_reset(struct vpu_subdev_data *data)
|
|||
try_reset_deassert(pservice->rst_cabac);
|
||||
|
||||
rockchip_pmu_idle_request(pservice->dev, false);
|
||||
clk_set_rate(pservice->aclk_vcodec, rate);
|
||||
dev_info(pservice->dev, "reset done\n");
|
||||
#endif
|
||||
}
|
||||
|
||||
static void dvfs_rkvdec_set_clk(u32 vcodec_rate, u32 core_rate, u32 cabac_rate)
|
||||
{
|
||||
/* todo */
|
||||
}
|
||||
|
||||
static void vpu_reset(struct vpu_subdev_data *data)
|
||||
{
|
||||
struct vpu_service_info *pservice = data->pservice;
|
||||
|
|
@ -702,6 +709,16 @@ static void vpu_service_clear(struct vpu_subdev_data *data)
|
|||
wake_up(&session->wait);
|
||||
}
|
||||
|
||||
#if VCODEC_CLOCK_ENABLE
|
||||
static void set_div_clk(struct clk *clock, int divide)
|
||||
{
|
||||
struct clk *parent = clk_get_parent(clock);
|
||||
unsigned long rate = clk_get_rate(parent);
|
||||
|
||||
clk_set_rate(clock, (rate / divide) + 1);
|
||||
}
|
||||
#endif
|
||||
|
||||
static void vpu_service_power_off(struct vpu_service_info *pservice)
|
||||
{
|
||||
int total_running;
|
||||
|
|
@ -730,19 +747,8 @@ static void vpu_service_power_off(struct vpu_service_info *pservice)
|
|||
}
|
||||
}
|
||||
pservice->curr_mode = VCODEC_RUNNING_MODE_NONE;
|
||||
pm_runtime_put(pservice->dev);
|
||||
#if VCODEC_CLOCK_ENABLE
|
||||
if (pservice->pd_video)
|
||||
clk_disable_unprepare(pservice->pd_video);
|
||||
if (pservice->hclk_vcodec)
|
||||
clk_disable_unprepare(pservice->hclk_vcodec);
|
||||
if (pservice->aclk_vcodec)
|
||||
clk_disable_unprepare(pservice->aclk_vcodec);
|
||||
if (pservice->clk_core)
|
||||
clk_disable_unprepare(pservice->clk_core);
|
||||
if (pservice->clk_cabac)
|
||||
clk_disable_unprepare(pservice->clk_cabac);
|
||||
#endif
|
||||
if (pservice->hw_ops->power_off)
|
||||
pservice->hw_ops->power_off(pservice);
|
||||
|
||||
atomic_add(1, &pservice->power_off_cnt);
|
||||
wake_unlock(&pservice->wake_lock);
|
||||
|
|
@ -790,19 +796,8 @@ static void vpu_service_power_on(struct vpu_subdev_data *data,
|
|||
|
||||
dev_dbg(pservice->dev, "power on\n");
|
||||
|
||||
#if VCODEC_CLOCK_ENABLE
|
||||
if (pservice->aclk_vcodec)
|
||||
clk_prepare_enable(pservice->aclk_vcodec);
|
||||
if (pservice->hclk_vcodec)
|
||||
clk_prepare_enable(pservice->hclk_vcodec);
|
||||
if (pservice->clk_core)
|
||||
clk_prepare_enable(pservice->clk_core);
|
||||
if (pservice->clk_cabac)
|
||||
clk_prepare_enable(pservice->clk_cabac);
|
||||
if (pservice->pd_video)
|
||||
clk_prepare_enable(pservice->pd_video);
|
||||
#endif
|
||||
pm_runtime_get_sync(pservice->dev);
|
||||
if (pservice->hw_ops->power_on)
|
||||
pservice->hw_ops->power_on(pservice);
|
||||
|
||||
udelay(5);
|
||||
atomic_add(1, &pservice->power_on_cnt);
|
||||
|
|
@ -1106,30 +1101,6 @@ static int vcodec_reg_address_translate(struct vpu_subdev_data *data,
|
|||
return -EINVAL;
|
||||
}
|
||||
|
||||
static void get_reg_freq(struct vpu_subdev_data *data, struct vpu_reg *reg)
|
||||
{
|
||||
|
||||
if (!of_machine_is_compatible("rockchip,rk2928g")) {
|
||||
if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {
|
||||
if (reg_check_fmt(reg) == VPU_DEC_FMT_H264) {
|
||||
if (reg_probe_width(reg) > 3200) {
|
||||
/*raise frequency for 4k avc.*/
|
||||
reg->freq = VPU_FREQ_600M;
|
||||
}
|
||||
} else {
|
||||
if (reg_check_interlace(reg))
|
||||
reg->freq = VPU_FREQ_400M;
|
||||
}
|
||||
}
|
||||
if (data->hw_id == HEVC_ID) {
|
||||
if (reg_probe_hevc_y_stride(reg) > 60000)
|
||||
reg->freq = VPU_FREQ_400M;
|
||||
}
|
||||
if (reg->type == VPU_PP)
|
||||
reg->freq = VPU_FREQ_400M;
|
||||
}
|
||||
}
|
||||
|
||||
static struct vpu_reg *reg_init(struct vpu_subdev_data *data,
|
||||
struct vpu_session *session,
|
||||
void __user *src, u32 size)
|
||||
|
|
@ -1196,8 +1167,8 @@ static struct vpu_reg *reg_init(struct vpu_subdev_data *data,
|
|||
list_add_tail(®->session_link, &session->waiting);
|
||||
mutex_unlock(&pservice->lock);
|
||||
|
||||
if (pservice->auto_freq)
|
||||
get_reg_freq(data, reg);
|
||||
if (pservice->auto_freq && pservice->hw_ops->get_freq)
|
||||
pservice->hw_ops->get_freq(data, reg);
|
||||
|
||||
vpu_debug_leave();
|
||||
|
||||
|
|
@ -1344,45 +1315,6 @@ static void reg_from_run_to_done(struct vpu_subdev_data *data,
|
|||
vpu_debug_leave();
|
||||
}
|
||||
|
||||
static void vpu_service_set_freq(struct vpu_service_info *pservice,
|
||||
struct vpu_reg *reg)
|
||||
{
|
||||
enum VPU_FREQ curr = atomic_read(&pservice->freq_status);
|
||||
|
||||
if (curr == reg->freq)
|
||||
return;
|
||||
|
||||
atomic_set(&pservice->freq_status, reg->freq);
|
||||
switch (reg->freq) {
|
||||
case VPU_FREQ_200M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 200 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_266M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 266 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_300M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 300 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_400M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 400 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_500M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 500 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_600M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 600 * MHZ);
|
||||
} break;
|
||||
default: {
|
||||
unsigned long rate = 300*MHZ;
|
||||
|
||||
if (of_machine_is_compatible("rockchip,rk2928g"))
|
||||
rate = 400*MHZ;
|
||||
|
||||
clk_set_rate(pservice->aclk_vcodec, rate);
|
||||
} break;
|
||||
}
|
||||
}
|
||||
|
||||
static void reg_copy_to_hw(struct vpu_subdev_data *data, struct vpu_reg *reg)
|
||||
{
|
||||
struct vpu_service_info *pservice = data->pservice;
|
||||
|
|
@ -1399,8 +1331,8 @@ static void reg_copy_to_hw(struct vpu_subdev_data *data, struct vpu_reg *reg)
|
|||
atomic_add(1, &pservice->total_running);
|
||||
atomic_add(1, ®->session->task_running);
|
||||
|
||||
if (pservice->auto_freq)
|
||||
vpu_service_set_freq(pservice, reg);
|
||||
if (pservice->auto_freq && pservice->hw_ops->set_freq)
|
||||
pservice->hw_ops->set_freq(pservice, reg);
|
||||
|
||||
vcodec_enter_mode(data);
|
||||
|
||||
|
|
@ -1460,6 +1392,7 @@ static void reg_copy_to_hw(struct vpu_subdev_data *data, struct vpu_reg *reg)
|
|||
if (pservice->dev_id == VCODEC_DEVICE_ID_RKVDEC) {
|
||||
u32 *cache_base = dst + 0x100;
|
||||
u32 val = (debug & DEBUG_CACHE_32B) ? (0x3) : (0x13);
|
||||
|
||||
writel_relaxed(val, cache_base + 0x07);
|
||||
writel_relaxed(val, cache_base + 0x17);
|
||||
}
|
||||
|
|
@ -1477,6 +1410,9 @@ static void reg_copy_to_hw(struct vpu_subdev_data *data, struct vpu_reg *reg)
|
|||
writel_relaxed(src[i], dst + i);
|
||||
}
|
||||
|
||||
if (pservice->hw_var && pservice->hw_var->config)
|
||||
pservice->hw_var->config(data);
|
||||
|
||||
writel(src[reg_en] | gating_mask, dst + reg_en);
|
||||
dsb(sy);
|
||||
|
||||
|
|
@ -1626,6 +1562,9 @@ static void try_set_reg(struct vpu_subdev_data *data)
|
|||
reg_from_wait_to_run(pservice, reg);
|
||||
reg_copy_to_hw(reg->data, reg);
|
||||
}
|
||||
} else {
|
||||
if (pservice->hw_ops->reduce_freq)
|
||||
pservice->hw_ops->reduce_freq(pservice);
|
||||
}
|
||||
|
||||
mutex_unlock(&pservice->shutdown_lock);
|
||||
|
|
@ -2081,6 +2020,214 @@ static struct device *rockchip_get_sysmmu_dev(const char *compt)
|
|||
return ret;
|
||||
}
|
||||
|
||||
/* special hw ops */
|
||||
static void vcodec_power_on_default(struct vpu_service_info *pservice)
|
||||
{
|
||||
#if VCODEC_CLOCK_ENABLE
|
||||
if (pservice->aclk_vcodec)
|
||||
clk_prepare_enable(pservice->aclk_vcodec);
|
||||
if (pservice->hclk_vcodec)
|
||||
clk_prepare_enable(pservice->hclk_vcodec);
|
||||
if (pservice->clk_core)
|
||||
clk_prepare_enable(pservice->clk_core);
|
||||
if (pservice->clk_cabac)
|
||||
clk_prepare_enable(pservice->clk_cabac);
|
||||
if (pservice->pd_video)
|
||||
clk_prepare_enable(pservice->pd_video);
|
||||
#endif
|
||||
pm_runtime_get_sync(pservice->dev);
|
||||
}
|
||||
|
||||
static void vcodec_power_on_rk312x(struct vpu_service_info *pservice)
|
||||
{
|
||||
#define BIT_VCODEC_CLK_SEL BIT(10)
|
||||
if (of_machine_is_compatible("rockchip,rk3126") ||
|
||||
of_machine_is_compatible("rockchip,rk3128"))
|
||||
regmap_write(pservice->grf, RK312X_GRF_SOC_CON1,
|
||||
BIT_VCODEC_CLK_SEL |
|
||||
(BIT_VCODEC_CLK_SEL << 16));
|
||||
|
||||
vcodec_power_on_default(pservice);
|
||||
}
|
||||
|
||||
static void vcodec_power_on_rk322x(struct vpu_service_info *pservice)
|
||||
{
|
||||
unsigned long rate = 300 * MHZ;
|
||||
|
||||
vcodec_power_on_default(pservice);
|
||||
|
||||
if (pservice->dev_id == VCODEC_DEVICE_ID_RKVDEC)
|
||||
rate = 500 * MHZ;
|
||||
|
||||
if (pservice->aclk_vcodec)
|
||||
clk_set_rate(pservice->aclk_vcodec, rate);
|
||||
if (pservice->clk_core)
|
||||
clk_set_rate(pservice->clk_core, 300 * MHZ);
|
||||
if (pservice->clk_cabac)
|
||||
clk_set_rate(pservice->clk_cabac, 300 * MHZ);
|
||||
}
|
||||
|
||||
static void vcodec_power_on_rk3328(struct vpu_service_info *pservice)
|
||||
{
|
||||
dvfs_rkvdec_set_clk(500 * MHZ, 250 * MHZ, 400 * MHZ);
|
||||
vcodec_power_on_default(pservice);
|
||||
}
|
||||
|
||||
static void vcodec_power_off_default(struct vpu_service_info *pservice)
|
||||
{
|
||||
if (pservice->pd_video)
|
||||
clk_disable_unprepare(pservice->pd_video);
|
||||
if (pservice->hclk_vcodec)
|
||||
clk_disable_unprepare(pservice->hclk_vcodec);
|
||||
if (pservice->aclk_vcodec)
|
||||
clk_disable_unprepare(pservice->aclk_vcodec);
|
||||
if (pservice->clk_core)
|
||||
clk_disable_unprepare(pservice->clk_core);
|
||||
if (pservice->clk_cabac)
|
||||
clk_disable_unprepare(pservice->clk_cabac);
|
||||
pm_runtime_get_sync(pservice->dev);
|
||||
}
|
||||
|
||||
static void vcodec_power_off_rk322x(struct vpu_service_info *pservice)
|
||||
{
|
||||
/*
|
||||
* rk322x do not have power domain
|
||||
* we just lower the clock to minimize the power consumption
|
||||
*/
|
||||
if (pservice->aclk_vcodec)
|
||||
set_div_clk(pservice->aclk_vcodec, 32);
|
||||
if (pservice->clk_core)
|
||||
set_div_clk(pservice->clk_core, 32);
|
||||
if (pservice->clk_cabac)
|
||||
set_div_clk(pservice->clk_cabac, 32);
|
||||
}
|
||||
|
||||
static void vcodec_power_off_rk3328(struct vpu_service_info *pservice)
|
||||
{
|
||||
vcodec_power_off_default(pservice);
|
||||
dvfs_rkvdec_set_clk(50 * MHZ, 50 * MHZ, 50 * MHZ);
|
||||
}
|
||||
|
||||
static void vcodec_get_reg_freq_default(struct vpu_subdev_data *data,
|
||||
struct vpu_reg *reg)
|
||||
{
|
||||
if (reg->type == VPU_DEC || reg->type == VPU_DEC_PP) {
|
||||
if (reg_check_fmt(reg) == VPU_DEC_FMT_H264) {
|
||||
if (reg_probe_width(reg) > 2560) {
|
||||
/*
|
||||
* raise frequency for resolution larger
|
||||
* than 1440p avc.
|
||||
*/
|
||||
reg->freq = VPU_FREQ_600M;
|
||||
}
|
||||
} else {
|
||||
if (reg_check_interlace(reg))
|
||||
reg->freq = VPU_FREQ_400M;
|
||||
}
|
||||
}
|
||||
if (data->hw_id == HEVC_ID) {
|
||||
if (reg_probe_hevc_y_stride(reg) > 60000)
|
||||
reg->freq = VPU_FREQ_400M;
|
||||
}
|
||||
if (reg->type == VPU_PP)
|
||||
reg->freq = VPU_FREQ_400M;
|
||||
}
|
||||
|
||||
static void vcodec_set_freq_default(struct vpu_service_info *pservice,
|
||||
struct vpu_reg *reg)
|
||||
{
|
||||
enum VPU_FREQ curr = atomic_read(&pservice->freq_status);
|
||||
|
||||
if (curr == reg->freq)
|
||||
return;
|
||||
|
||||
atomic_set(&pservice->freq_status, reg->freq);
|
||||
switch (reg->freq) {
|
||||
case VPU_FREQ_200M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 200 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_266M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 266 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_300M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 300 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_400M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 400 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_500M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 500 * MHZ);
|
||||
} break;
|
||||
case VPU_FREQ_600M: {
|
||||
clk_set_rate(pservice->aclk_vcodec, 600 * MHZ);
|
||||
} break;
|
||||
default: {
|
||||
clk_set_rate(pservice->aclk_vcodec,
|
||||
pservice->aclk_vcodec_default_rate);
|
||||
clk_set_rate(pservice->clk_core,
|
||||
pservice->clk_core_default_rate);
|
||||
clk_set_rate(pservice->clk_cabac,
|
||||
pservice->clk_cabac_default_rate);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vcodec_set_freq_rk3328(struct vpu_service_info *pservice,
|
||||
struct vpu_reg *reg)
|
||||
{
|
||||
enum VPU_FREQ curr = atomic_read(&pservice->freq_status);
|
||||
|
||||
if (curr == reg->freq)
|
||||
return;
|
||||
|
||||
if (pservice->dev_id == VCODEC_DEVICE_ID_RKVDEC) {
|
||||
if (reg->reg[1] & 0x00800000) {
|
||||
if (rkv_dec_get_fmt(reg->reg) == FMT_H264D) {
|
||||
clk_set_rate(pservice->aclk_vcodec, 400 * MHZ);
|
||||
clk_set_rate(pservice->clk_core, 250 * MHZ);
|
||||
clk_set_rate(pservice->clk_cabac, 400 * MHZ);
|
||||
} else {
|
||||
clk_set_rate(pservice->aclk_vcodec, 500 * MHZ);
|
||||
clk_set_rate(pservice->clk_core, 250 * MHZ);
|
||||
clk_set_rate(pservice->clk_cabac, 400 * MHZ);
|
||||
}
|
||||
} else {
|
||||
if (rkv_dec_get_fmt(reg->reg) == FMT_H264D) {
|
||||
clk_set_rate(pservice->aclk_vcodec, 400 * MHZ);
|
||||
clk_set_rate(pservice->clk_core, 300 * MHZ);
|
||||
clk_set_rate(pservice->clk_cabac, 400 * MHZ);
|
||||
} else {
|
||||
clk_set_rate(pservice->aclk_vcodec, 500 * MHZ);
|
||||
clk_set_rate(pservice->clk_core, 300 * MHZ);
|
||||
clk_set_rate(pservice->clk_cabac, 400 * MHZ);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static void vcodec_set_freq_rk322x(struct vpu_service_info *pservice,
|
||||
struct vpu_reg *reg)
|
||||
{
|
||||
enum VPU_FREQ curr = atomic_read(&pservice->freq_status);
|
||||
|
||||
if (curr == reg->freq)
|
||||
return;
|
||||
|
||||
/*
|
||||
* special process for rk322x
|
||||
* rk322x rkvdec has more clocks to set
|
||||
* vpu/vpu2 still only need to set aclk
|
||||
*/
|
||||
if (pservice->dev_id == VCODEC_DEVICE_ID_RKVDEC) {
|
||||
clk_set_rate(pservice->clk_core, 300 * MHZ);
|
||||
clk_set_rate(pservice->clk_cabac, 300 * MHZ);
|
||||
clk_set_rate(pservice->aclk_vcodec, 500 * MHZ);
|
||||
} else {
|
||||
clk_set_rate(pservice->aclk_vcodec, 300 * MHZ);
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef CONFIG_IOMMU_API
|
||||
static inline void platform_set_sysmmu(struct device *iommu,
|
||||
struct device *dev)
|
||||
|
|
@ -2165,6 +2312,119 @@ int vcodec_sysmmu_fault_hdl(struct device *dev,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static int vcodec_spec_init_rk3328(struct vpu_service_info *pservice)
|
||||
{
|
||||
/* todo */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void vcodec_spec_config_rk3328(struct vpu_subdev_data *data)
|
||||
{
|
||||
u32 *dst = data->dec_dev.regs;
|
||||
struct vpu_reg *reg = data->pservice->reg_codec;
|
||||
u32 cfg;
|
||||
|
||||
/*
|
||||
* HW defeat workaround: VP9 power save optimization cause decoding
|
||||
* corruption, disable optimization here.
|
||||
*/
|
||||
if (rkv_dec_get_fmt(reg->reg) == FMT_VP9D) {
|
||||
cfg = readl(dst + 99);
|
||||
writel(cfg & (~(1 << 12)), dst + 99);
|
||||
}
|
||||
}
|
||||
|
||||
static struct vcodec_hw_ops hw_ops_default = {
|
||||
.power_on = vcodec_power_on_default,
|
||||
.power_off = vcodec_power_off_default,
|
||||
.get_freq = vcodec_get_reg_freq_default,
|
||||
.set_freq = vcodec_set_freq_default,
|
||||
.reduce_freq = NULL,
|
||||
};
|
||||
|
||||
static struct vcodec_hw_ops hw_ops_rk3328_rkvdec = {
|
||||
.power_on = vcodec_power_on_rk3328,
|
||||
.power_off = vcodec_power_off_rk3328,
|
||||
.get_freq = vcodec_get_reg_freq_default,
|
||||
.set_freq = vcodec_set_freq_rk3328,
|
||||
.reduce_freq = NULL,
|
||||
};
|
||||
|
||||
static struct vcodec_hw_var rk3328_rkvdec_var = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_RKVD,
|
||||
.name = "rkvdec",
|
||||
.pmu_type = -1,
|
||||
.ops = &hw_ops_rk3328_rkvdec,
|
||||
.init = vcodec_spec_init_rk3328,
|
||||
.config = vcodec_spec_config_rk3328,
|
||||
};
|
||||
|
||||
static struct vcodec_hw_var rk3328_vpucombo_var = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_VPUC,
|
||||
.name = "vpu-combo",
|
||||
.pmu_type = -1,
|
||||
.ops = &hw_ops_default,
|
||||
.init = NULL,
|
||||
.config = NULL,
|
||||
};
|
||||
|
||||
/* Both VPU1 and VPU2 */
|
||||
static struct vcodec_hw_var vpu_device_info = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_VPUX,
|
||||
.name = "vpu-service",
|
||||
.pmu_type = -1,
|
||||
.ops = &hw_ops_default,
|
||||
.init = NULL,
|
||||
.config = NULL,
|
||||
};
|
||||
|
||||
static struct vcodec_hw_var vpu_combo_device_info = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_VPUC,
|
||||
.name = "vpu-combo",
|
||||
.pmu_type = -1,
|
||||
.ops = &hw_ops_default,
|
||||
.init = NULL,
|
||||
.config = NULL,
|
||||
};
|
||||
|
||||
static struct vcodec_hw_var hevc_device_info = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_HEVC,
|
||||
.name = "hevc-service",
|
||||
.pmu_type = -1,
|
||||
.ops = &hw_ops_default,
|
||||
.init = NULL,
|
||||
.config = NULL,
|
||||
};
|
||||
|
||||
static struct vcodec_hw_var rkvd_device_info = {
|
||||
.device_type = VCODEC_DEVICE_TYPE_RKVD,
|
||||
.name = "rkvdec",
|
||||
.pmu_type = -1,
|
||||
.ops = &hw_ops_default,
|
||||
.init = NULL,
|
||||
.config = NULL,
|
||||
};
|
||||
|
||||
static void vcodec_set_hw_ops(struct vpu_service_info *pservice)
|
||||
{
|
||||
if (pservice->hw_var) {
|
||||
pservice->hw_ops = pservice->hw_var->ops;
|
||||
} else {
|
||||
pservice->hw_ops = &hw_ops_default;
|
||||
if (of_machine_is_compatible("rockchip,rk3328") ||
|
||||
of_machine_is_compatible("rockchip,rk3228") ||
|
||||
of_machine_is_compatible("rockchip,rk3229")) {
|
||||
pservice->hw_ops->power_on = vcodec_power_on_rk322x;
|
||||
pservice->hw_ops->power_off = vcodec_power_off_rk322x;
|
||||
pservice->hw_ops->get_freq = NULL;
|
||||
pservice->hw_ops->set_freq = vcodec_set_freq_rk322x;
|
||||
} else if (of_machine_is_compatible("rockchip,rk3126") ||
|
||||
of_machine_is_compatible("rockchip,rk3128")) {
|
||||
pservice->hw_ops->power_on = vcodec_power_on_rk312x;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static int vcodec_subdev_probe(struct platform_device *pdev,
|
||||
struct vpu_service_info *pservice)
|
||||
{
|
||||
|
|
@ -2260,7 +2520,8 @@ static int vcodec_subdev_probe(struct platform_device *pdev,
|
|||
if (of_machine_is_compatible("rockchip,rk3126") ||
|
||||
of_machine_is_compatible("rockchip,rk3128"))
|
||||
regmap_write(pservice->grf, RK312X_GRF_SOC_CON1,
|
||||
BIT_VCODEC_CLK_SEL | (BIT_VCODEC_CLK_SEL << 16));
|
||||
BIT_VCODEC_CLK_SEL |
|
||||
(BIT_VCODEC_CLK_SEL << 16));
|
||||
|
||||
clear_bit(MMU_ACTIVATED, &data->state);
|
||||
vpu_service_power_on(data, pservice);
|
||||
|
|
@ -2467,8 +2728,37 @@ static void vcodec_read_property(struct device_node *np,
|
|||
of_property_read_string(np, "name", (const char **)&pservice->name);
|
||||
}
|
||||
|
||||
static const struct of_device_id vcodec_service_dt_ids[] = {
|
||||
{
|
||||
.compatible = "rockchip,rk3328-rkvdec",
|
||||
.data = &rk3328_rkvdec_var,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rk3328-vpu-combo",
|
||||
.data = &rk3328_vpucombo_var,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,vpu_service",
|
||||
.data = &vpu_device_info,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,hevc_service",
|
||||
.data = &hevc_device_info,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,vpu_combo",
|
||||
.data = &vpu_combo_device_info,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rkvdec",
|
||||
.data = &rkvd_device_info,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
static void vcodec_init_drvdata(struct vpu_service_info *pservice)
|
||||
{
|
||||
const struct of_device_id *match = NULL;
|
||||
pservice->dev_id = VCODEC_DEVICE_ID_VPU;
|
||||
pservice->curr_mode = -1;
|
||||
|
||||
|
|
@ -2494,7 +2784,15 @@ static void vcodec_init_drvdata(struct vpu_service_info *pservice)
|
|||
INIT_DELAYED_WORK(&pservice->power_off_work, vpu_power_off_work);
|
||||
pservice->last.tv64 = 0;
|
||||
|
||||
match = of_match_node(vcodec_service_dt_ids, pservice->dev->of_node);
|
||||
if (match)
|
||||
pservice->hw_var = match->data;
|
||||
|
||||
pservice->alloc_type = 0;
|
||||
|
||||
vcodec_set_hw_ops(pservice);
|
||||
if (pservice->hw_var && pservice->hw_var->init)
|
||||
pservice->hw_var->init(pservice);
|
||||
}
|
||||
|
||||
static int vcodec_probe(struct platform_device *pdev)
|
||||
|
|
@ -2653,26 +2951,6 @@ static void vcodec_shutdown(struct platform_device *pdev)
|
|||
pm_runtime_disable(&pdev->dev);
|
||||
}
|
||||
|
||||
static const struct of_device_id vcodec_service_dt_ids[] = {
|
||||
{
|
||||
.compatible = "rockchip,vpu_service",
|
||||
.data = &vpu_device_info,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,hevc_service",
|
||||
.data = &hevc_device_info,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,vpu_combo",
|
||||
.data = &vpu_combo_device_info,
|
||||
},
|
||||
{
|
||||
.compatible = "rockchip,rkvdec",
|
||||
.data = &rkvd_device_info,
|
||||
},
|
||||
{},
|
||||
};
|
||||
|
||||
MODULE_DEVICE_TABLE(of, vcodec_service_dt_ids);
|
||||
|
||||
static void *vcodec_get_drv_data(struct platform_device *pdev)
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user