From 7dd2bd23a830fbffb07886bad60527aab46bf35c Mon Sep 17 00:00:00 2001 From: Evoke Zhang Date: Thu, 24 Nov 2016 10:32:14 +0800 Subject: [PATCH] vpu: add vpu driver PD#138714: initial add vpu driver Change-Id: I84a8c00082b393f417ffdd1a155346cc6272743b Signed-off-by: Evoke Zhang Signed-off-by: Jianxin Pan --- MAINTAINERS | 4 + arch/arm64/boot/dts/amlogic/mesongxl.dtsi | 10 ++ arch/arm64/boot/dts/amlogic/mesongxm.dtsi | 10 ++ arch/arm64/configs/meson64_defconfig | 1 + drivers/amlogic/media/common/vpu/vpu.c | 89 ++++++------ drivers/amlogic/media/common/vpu/vpu_ctrl.c | 4 +- drivers/amlogic/media/common/vpu/vpu_reg.c | 149 ++++++++++++-------- drivers/amlogic/media/common/vpu/vpu_reg.h | 9 -- 8 files changed, 161 insertions(+), 115 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index 9a1059b9977a..6cac5a1db7c5 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -13531,3 +13531,7 @@ F: drivers/amlogic/media/common/frame_sync/* F: drivers/amlogic/media/common/ge2d/* F: drivers/amlogic/media/common/vpu/* +AMLOGIC VPU driver support +M: Evoke Zhang +F: drivers/amlogic/vpu/* +F: include/linux/amlogic/vpu.h diff --git a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi index fbb9f0c80bdf..072799701ec1 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxl.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxl.dtsi @@ -210,6 +210,16 @@ #clock-cells = <0>; }; + vpu { + compatible = "amlogic, vpu"; + dev_name = "vpu"; + status = "ok"; + clocks = <&clkc CLKID_VPU_MUX &clkc CLKID_VAPB_MUX>; + clock-names = "vpu_clk", "vapb_clk"; + clk_level = <7>; + /* 0: 100.0M 1: 166.7M 2: 200.0M 3: 250.0M */ + /* 4: 333.3M 5: 400.0M 6: 500.0M 7: 666.7M */ + }; i2c_ao: i2c@c8100500{ /*I2C-AO*/ compatible = "amlogic, meson-i2c"; dev_name = "i2c-AO"; diff --git a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi index ba2880229fcc..5eef6f55dab2 100644 --- a/arch/arm64/boot/dts/amlogic/mesongxm.dtsi +++ b/arch/arm64/boot/dts/amlogic/mesongxm.dtsi @@ -263,6 +263,16 @@ #clock-cells = <0>; }; + vpu { + compatible = "amlogic, vpu"; + dev_name = "vpu"; + status = "ok"; + clocks = <&clkc CLKID_VPU_MUX &clkc CLKID_VAPB_MUX>; + clock-names = "vpu_clk", "vapb_clk"; + clk_level = <7>; + /* 0: 100.0M 1: 166.7M 2: 200.0M 3: 250.0M */ + /* 4: 333.3M 5: 400.0M 6: 500.0M 7: 666.7M */ + }; i2c_ao: i2c@c8100500{ /*I2C-AO*/ compatible = "amlogic, meson-i2c"; dev_name = "i2c-AO"; diff --git a/arch/arm64/configs/meson64_defconfig b/arch/arm64/configs/meson64_defconfig index 9a9ed443f1bc..961fc45485a6 100644 --- a/arch/arm64/configs/meson64_defconfig +++ b/arch/arm64/configs/meson64_defconfig @@ -194,6 +194,7 @@ CONFIG_AMLOGIC_MEDIA_CODEC_MM=y CONFIG_AMLOGIC_MEDIA_CANVAS=y CONFIG_AMLOGIC_ION=y CONFIG_AMLOGIC_MEDIA_VFM=y +CONFIG_AMLOGIC_VPU=y CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug" CONFIG_DEVTMPFS=y CONFIG_DEVTMPFS_MOUNT=y diff --git a/drivers/amlogic/media/common/vpu/vpu.c b/drivers/amlogic/media/common/vpu/vpu.c index e7f24a8546f7..86b126b80d4f 100644 --- a/drivers/amlogic/media/common/vpu/vpu.c +++ b/drivers/amlogic/media/common/vpu/vpu.c @@ -24,8 +24,10 @@ #include #include #include +#include +#include #include -#include +#include #include "vpu_reg.h" #include "vpu.h" #include "vpu_clk.h" @@ -137,14 +139,12 @@ static unsigned int get_vpu_clk_level(unsigned int video_clk) unsigned int get_vpu_clk(void) { - unsigned int reg; unsigned int clk_freq; unsigned int fclk, clk_source; unsigned int mux, div; - reg = HHI_VPU_CLK_CNTL; fclk = CLK_FPLL_FREQ * 100; /* 0.01M resolution */ - mux = vpu_hiu_getb(reg, 9, 3); + mux = vpu_hiu_getb(HHI_VPU_CLK_CNTL, 9, 3); switch (mux) { case FCLK_DIV4: case FCLK_DIV3: @@ -163,7 +163,7 @@ unsigned int get_vpu_clk(void) break; } - div = vpu_hiu_getb(reg, 0, 7) + 1; + div = vpu_hiu_getb(HHI_VPU_CLK_CNTL, 0, 7) + 1; clk_freq = (clk_source / div) * 10 * 1000; /* change to Hz */ return clk_freq; @@ -226,7 +226,6 @@ static int adjust_vpu_clk(unsigned int clk_level) { unsigned long flags = 0; unsigned int mux, div; - unsigned int vpu_clk; int ret = 0; ret = vpu_chip_valid_check(); @@ -246,6 +245,7 @@ static int adjust_vpu_clk(unsigned int clk_level) } vpu_conf.clk_level = clk_level; + /* step 1: switch to 2nd vpu clk patch */ mux = vpu_clk_table[0][1]; vpu_hiu_setb(HHI_VPU_CLK_CNTL, mux, 25, 3); @@ -266,15 +266,9 @@ static int adjust_vpu_clk(unsigned int clk_level) vpu_hiu_setb(HHI_VPU_CLK_CNTL, 0, 31, 1); vpu_hiu_setb(HHI_VPU_CLK_CNTL, 0, 24, 1); - vpu_clk = vpu_clk_table[vpu_conf.clk_level][0]; - if (vpu_clk >= (VPU_CLKB_MAX * 1000000)) - div = 2; - else - div = 1; - vpu_hiu_setb(HHI_VPU_CLKB_CNTL, (div - 1), 0, 8); - VPUPR("set vpu clk: %uHz, readback: %uHz(0x%x)\n", - vpu_clk, get_vpu_clk(), (vpu_hiu_read(HHI_VPU_CLK_CNTL))); + vpu_clk_table[vpu_conf.clk_level][0], + get_vpu_clk(), (vpu_hiu_read(HHI_VPU_CLK_CNTL))); spin_unlock_irqrestore(&vpu_lock, flags); return ret; @@ -283,7 +277,6 @@ static int adjust_vpu_clk(unsigned int clk_level) static int set_vpu_clk(unsigned int vclk) { int ret = 0; - unsigned int reg; unsigned int clk_level, mux, div; mutex_lock(&vpu_mutex); @@ -306,9 +299,8 @@ static int set_vpu_clk(unsigned int vclk) #endif } - reg = HHI_VPU_CLK_CNTL; - mux = vpu_hiu_getb(reg, 9, 3); - div = vpu_hiu_getb(reg, 0, 7); + mux = vpu_hiu_getb(HHI_VPU_CLK_CNTL, 9, 3); + div = vpu_hiu_getb(HHI_VPU_CLK_CNTL, 0, 7); if ((mux != vpu_clk_table[clk_level][1]) || (div != vpu_clk_table[clk_level][2])) { ret = adjust_vpu_clk(clk_level); @@ -340,7 +332,6 @@ set_vpu_clk_limit: */ unsigned int get_vpu_clk_vmod(unsigned int vmod) { - unsigned int vpu_mod; unsigned int vpu_clk; int ret = 0; @@ -350,9 +341,8 @@ unsigned int get_vpu_clk_vmod(unsigned int vmod) mutex_lock(&vpu_mutex); - vpu_mod = vmod; - if (vpu_mod < VPU_MAX) { - vpu_clk = clk_vmod[vpu_mod]; + if (vmod < VPU_MAX) { + vpu_clk = clk_vmod[vmod]; vpu_clk = vpu_clk_table[vpu_clk][0]; } else { vpu_clk = 0; @@ -387,7 +377,6 @@ int request_vpu_clk_vmod(unsigned int vclk, unsigned int vmod) int ret = 0; #ifdef CONFIG_VPU_DYNAMIC_ADJ unsigned int clk_level; - unsigned int vpu_mod; ret = vpu_chip_valid_check(); if (ret) @@ -406,17 +395,16 @@ int request_vpu_clk_vmod(unsigned int vclk, unsigned int vmod) goto request_vpu_clk_limit; } - vpu_mod = vmod; - if (vpu_mod == VPU_MAX) { + if (vmod == VPU_MAX) { ret = 1; VPUERR("unsupport vmod\n"); goto request_vpu_clk_limit; } - clk_vmod[vpu_mod] = clk_level; + clk_vmod[vmod] = clk_level; if (vpu_debug_print_flag) { VPUPR("request vpu clk: %s %uHz\n", - vpu_mod_table[vpu_mod], + vpu_mod_table[vmod], vpu_clk_table[clk_level][0]); dump_stack(); } @@ -454,7 +442,6 @@ int release_vpu_clk_vmod(unsigned int vmod) int ret = 0; #ifdef CONFIG_VPU_DYNAMIC_ADJ unsigned int clk_level; - unsigned int vpu_mod; ret = vpu_chip_valid_check(); if (ret) @@ -463,17 +450,16 @@ int release_vpu_clk_vmod(unsigned int vmod) mutex_lock(&vpu_mutex); clk_level = 0; - vpu_mod = vmod; - if (vpu_mod == VPU_MAX) { + if (vmod == VPU_MAX) { ret = 1; VPUERR("unsupport vmod\n"); goto release_vpu_clk_limit; } - clk_vmod[vpu_mod] = clk_level; + clk_vmod[vmod] = clk_level; if (vpu_debug_print_flag) { VPUPR("release vpu clk: %s\n", - vpu_mod_table[vpu_mod]); + vpu_mod_table[vmod]); dump_stack(); } @@ -513,8 +499,8 @@ static const char *vpu_usage_str = { " request & release will change vpu clk if the max level in all vmod vpu clk holdings is unequal to current vpu clk level.\n" " vclk both support level(1~10) and frequency value (unit in Hz).\n" " vclk level & frequency:\n" -" 0: 100M 1: 167M 2: 200M 3: 333M\n" -" 4: 400M 5: 500M 6: 667M 8: 696M\n" +" 0: 100M 1: 167M 2: 200M 3: 250M\n" +" 4: 333M 5: 400M 6: 500M 7: 667M\n" "\n" " echo <0|1> > print ; set debug print flag\n" }; @@ -561,16 +547,15 @@ static ssize_t vpu_clk_debug(struct class *class, struct class_attribute *attr, case 'd': tmp[0] = VPU_MAX; ret = sscanf(buf, "dump %u", &tmp[0]); - tmp[1] = tmp[0]; - if (tmp[1] == VPU_MAX) { + if (tmp[0] == VPU_MAX) { n = get_vpu_clk_level_max_vmod(); VPUPR("clk max holdings: %uHz(%u)\n", vpu_clk_table[n][0], n); } else { VPUPR("clk holdings:\n"); - pr_info("%s: %uHz(%u)\n", vpu_mod_table[tmp[1]], - vpu_clk_table[clk_vmod[tmp[1]]][0], - clk_vmod[tmp[1]]); + pr_info("%s: %uHz(%u)\n", vpu_mod_table[tmp[0]], + vpu_clk_table[clk_vmod[tmp[0]]][0], + clk_vmod[tmp[0]]); } break; default: @@ -675,10 +660,10 @@ static ssize_t vpu_clk_gate_debug(struct class *class, } static unsigned int vcbus_reg[] = { - 0x1d00, /* VPP_DUMMY_DATA */ - 0x1702, /* DI_POST_SIZE */ + 0x1b7f, /* VENC_VDAC_TST_VAL */ 0x1c30, /* ENCP_DVI_HSO_BEGIN */ - 0x1b78, /* VENC_VDAC_DACSEL0 */ + 0x1d00, /* VPP_DUMMY_DATA */ + 0x2730, /* VPU_VPU_PWM_V0 */ }; static void vcbus_test(void) @@ -822,6 +807,25 @@ static int get_vpu_config(struct platform_device *pdev) return ret; } +static void vpu_clktree_init(struct device *dev) +{ + static struct clk *vpu_clktree; + + vpu_clktree = devm_clk_get(dev, "vapb_clk"); + if (IS_ERR(vpu_clktree)) + VPUERR("%s: vapb_clk\n", __func__); + else + clk_prepare_enable(vpu_clktree); + + vpu_clktree = devm_clk_get(dev, "vpu_clk"); + if (IS_ERR(vpu_clktree)) + VPUERR("%s: vpu_clk\n", __func__); + else + clk_prepare_enable(vpu_clktree); + + VPUPR("%s\n", __func__); +} + static const struct of_device_id vpu_of_table[] = { { .compatible = "amlogic, vpu", @@ -852,6 +856,7 @@ static int vpu_probe(struct platform_device *pdev) vpu_ctrl_probe(); set_vpu_clk(vpu_conf.clk_level); + vpu_clktree_init(&pdev->dev); creat_vpu_debug_class(); diff --git a/drivers/amlogic/media/common/vpu/vpu_ctrl.c b/drivers/amlogic/media/common/vpu/vpu_ctrl.c index 06ccd7d7af79..74b377e6b1be 100644 --- a/drivers/amlogic/media/common/vpu/vpu_ctrl.c +++ b/drivers/amlogic/media/common/vpu/vpu_ctrl.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "vpu_reg.h" #include "vpu.h" #include "vpu_module.h" @@ -420,7 +420,7 @@ void switch_vpu_clk_gate_vmod(unsigned int vmod, int flag) break; case VPU_VENC_DAC: /* clk for dac(r/w reg) */ - vpu_vcbus_setb(VPU_CLK_GATE, val, 12, 1); + /*vpu_vcbus_setb(VPU_CLK_GATE, val, 12, 1);*/ vpu_hiu_setb(HHI_GCLK_OTHER, val, 10, 1); /* dac top clk */ break; case VPU_VENCP: diff --git a/drivers/amlogic/media/common/vpu/vpu_reg.c b/drivers/amlogic/media/common/vpu/vpu_reg.c index e024f19a3029..eca999d13970 100644 --- a/drivers/amlogic/media/common/vpu/vpu_reg.c +++ b/drivers/amlogic/media/common/vpu/vpu_reg.c @@ -21,7 +21,7 @@ #include #include #include -#include +#include #include "vpu_reg.h" #include "vpu.h" @@ -30,6 +30,9 @@ * ********************************* */ +#define VPU_MAP_HIUBUS 0 +#define VPU_MAP_VCBUS 1 + struct reg_map_s { unsigned int base_addr; unsigned int size; @@ -37,11 +40,10 @@ struct reg_map_s { int flag; }; +static struct reg_map_s *vpu_map; +static int vpu_map_num; + static struct reg_map_s vpu_reg_maps[] = { - { /* CBUS */ - .base_addr = 0xc1100000, - .size = 0x10000, - }, { /* HIU */ .base_addr = 0xc883c000, .size = 0x400, @@ -57,40 +59,99 @@ int vpu_ioremap(void) int i; int ret = 0; - for (i = 0; i < ARRAY_SIZE(vpu_reg_maps); i++) { - vpu_reg_maps[i].p = ioremap(vpu_reg_maps[i].base_addr, - vpu_reg_maps[i].size); - if (vpu_reg_maps[i].p == NULL) { - vpu_reg_maps[i].flag = 0; + vpu_map = vpu_reg_maps; + vpu_map_num = ARRAY_SIZE(vpu_reg_maps); + + for (i = 0; i < vpu_map_num; i++) { + vpu_map[i].p = ioremap(vpu_map[i].base_addr, vpu_map[i].size); + if (vpu_map[i].p == NULL) { + vpu_map[i].flag = 0; VPUERR("VPU reg map failed: 0x%x\n", - vpu_reg_maps[i].base_addr); + vpu_map[i].base_addr); ret = -1; } else { - vpu_reg_maps[i].flag = 1; + vpu_map[i].flag = 1; #if 0 VPUPR("VPU reg mapped: 0x%x -> %p\n", - vpu_reg_maps[i].base_addr, - vpu_reg_maps[i].p); + vpu_map[i].base_addr, vpu_map[i].p); #endif } } return ret; } +static int vpu_ioremap_check(int n) +{ + if (vpu_map == NULL) + return -1; + if (n >= vpu_map_num) + return -1; + + if (vpu_map[n].flag == 0) { + VPUERR("reg 0x%x mapped error\n", vpu_map[n].base_addr); + return -1; + } + return 0; +} + +static void __iomem *vpu_hiu_reg_check(unsigned int _reg) +{ + void __iomem *p = NULL; + int reg_bus; + unsigned int reg_offset; + + reg_bus = VPU_MAP_HIUBUS; + if (vpu_ioremap_check(reg_bus)) + return NULL; + + reg_offset = REG_OFFSET_HIU(_reg); + if (reg_offset > vpu_map[reg_bus].size) { + VPUERR("invalid reg offset: 0x%02x\n", _reg); + return NULL; + } + p = vpu_map[reg_bus].p + reg_offset; + + return p; +} + +static void __iomem *vpu_vcbus_reg_check(unsigned int _reg) +{ + void __iomem *p = NULL; + int reg_bus; + unsigned int reg_offset; + + reg_bus = VPU_MAP_VCBUS; + if (vpu_ioremap_check(reg_bus)) + return NULL; + + reg_offset = REG_OFFSET_VCBUS(_reg); + if (reg_offset > vpu_map[reg_bus].size) { + VPUERR("invalid reg offset: 0x%04x\n", _reg); + return NULL; + } + p = vpu_map[reg_bus].p + reg_offset; + + return p; +} + unsigned int vpu_hiu_read(unsigned int _reg) { void __iomem *p; - p = vpu_reg_maps[1].p + REG_OFFSET_HIU(_reg); - return readl(p); + p = vpu_hiu_reg_check(_reg); + if (p) + return readl(p); + else + return 0; }; void vpu_hiu_write(unsigned int _reg, unsigned int _value) { void __iomem *p; - p = vpu_reg_maps[1].p + REG_OFFSET_HIU(_reg); - writel(_value, p); + p = vpu_hiu_reg_check(_reg); + if (p) + writel(_value, p); }; void vpu_hiu_setb(unsigned int _reg, unsigned int _value, @@ -117,60 +178,24 @@ void vpu_hiu_clr_mask(unsigned int _reg, unsigned int _mask) vpu_hiu_write(_reg, (vpu_hiu_read(_reg) & (~(_mask)))); } -unsigned int vpu_cbus_read(unsigned int _reg) -{ - void __iomem *p; - - p = vpu_reg_maps[0].p + REG_OFFSET_CBUS(_reg); - return readl(p); -}; - -void vpu_cbus_write(unsigned int _reg, unsigned int _value) -{ - void __iomem *p; - - p = vpu_reg_maps[0].p + REG_OFFSET_CBUS(_reg); - writel(_value, p); -}; - -void vpu_cbus_setb(unsigned int _reg, unsigned int _value, - unsigned int _start, unsigned int _len) -{ - vpu_cbus_write(_reg, ((vpu_cbus_read(_reg) & - ~(((1L << (_len))-1) << (_start))) | - (((_value)&((1L<<(_len))-1)) << (_start)))); -} - -unsigned int vpu_cbus_getb(unsigned int _reg, - unsigned int _start, unsigned int _len) -{ - return (vpu_cbus_read(_reg) >> (_start)) & ((1L << (_len)) - 1); -} - -void vpu_cbus_set_mask(unsigned int _reg, unsigned int _mask) -{ - vpu_cbus_write(_reg, (vpu_cbus_read(_reg) | (_mask))); -} - -void vpu_cbus_clr_mask(unsigned int _reg, unsigned int _mask) -{ - vpu_cbus_write(_reg, (vpu_cbus_read(_reg) & (~(_mask)))); -} - unsigned int vpu_vcbus_read(unsigned int _reg) { void __iomem *p; - p = vpu_reg_maps[2].p + REG_OFFSET_VCBUS(_reg); - return readl(p); + p = vpu_vcbus_reg_check(_reg); + if (p) + return readl(p); + else + return 0; }; void vpu_vcbus_write(unsigned int _reg, unsigned int _value) { void __iomem *p; - p = vpu_reg_maps[2].p + REG_OFFSET_VCBUS(_reg); - writel(_value, p); + p = vpu_vcbus_reg_check(_reg); + if (p) + writel(_value, p); }; void vpu_vcbus_setb(unsigned int _reg, unsigned int _value, diff --git a/drivers/amlogic/media/common/vpu/vpu_reg.h b/drivers/amlogic/media/common/vpu/vpu_reg.h index 845fa08ab4de..aa88a6fbd1ff 100644 --- a/drivers/amlogic/media/common/vpu/vpu_reg.h +++ b/drivers/amlogic/media/common/vpu/vpu_reg.h @@ -119,15 +119,6 @@ extern unsigned int vpu_hiu_getb(unsigned int _reg, extern void vpu_hiu_set_mask(unsigned int _reg, unsigned int _mask); extern void vpu_hiu_clr_mask(unsigned int _reg, unsigned int _mask); -extern unsigned int vpu_cbus_read(unsigned int _reg); -extern void vpu_cbus_write(unsigned int _reg, unsigned int _value); -extern void vpu_cbus_setb(unsigned int _reg, unsigned int _value, - unsigned int _start, unsigned int _len); -extern unsigned int vpu_cbus_getb(unsigned int _reg, - unsigned int _start, unsigned int _len); -extern void vpu_cbus_set_mask(unsigned int _reg, unsigned int _mask); -extern void vpu_cbus_clr_mask(unsigned int _reg, unsigned int _mask); - extern unsigned int vpu_vcbus_read(unsigned int _reg); extern void vpu_vcbus_write(unsigned int _reg, unsigned int _value); extern void vpu_vcbus_setb(unsigned int _reg, unsigned int _value,