From 653e8f98907d510252393cafebbc334bb475c26e Mon Sep 17 00:00:00 2001 From: SamulKyull Date: Sun, 8 Dec 2024 12:20:52 +0800 Subject: [PATCH] [bsp] update drivers --- bsp/.gitignore | 1 + bsp/drivers/Kconfig | 3 + bsp/drivers/Makefile | 3 + bsp/drivers/andes_adaptor/Kconfig | 42 +++ bsp/drivers/andes_adaptor/Makefile | 7 + bsp/drivers/andes_adaptor/cma_non_cacher.c | 110 ++++++ bsp/drivers/andes_adaptor/dma_ops_adapter.c | 245 ++++++++++++++ bsp/drivers/dma/sunxi-dma.c | 11 +- .../lowlevel_edp/inno_edp13/inno_edp13.c | 85 ++++- .../trilinear_dp14/trilinear_dp14.c | 221 ++++++++++-- .../hardware/lowlevel_hdmi20/dw_avp.c | 4 +- .../hardware/lowlevel_hdmi20/dw_cec.c | 4 +- .../hardware/lowlevel_hdmi20/dw_dev.c | 2 +- .../hardware/lowlevel_hdmi20/dw_dev.h | 14 + .../hardware/lowlevel_hdmi20/dw_hdcp.c | 302 +++++++---------- .../hardware/lowlevel_hdmi20/dw_hdcp.h | 12 +- .../hardware/lowlevel_hdmi20/dw_hdcp22.c | 245 +++++++------- .../hardware/lowlevel_hdmi20/dw_hdcp22.h | 12 + .../hardware/lowlevel_hdmi20/dw_mc.c | 73 ++-- .../hardware/lowlevel_hdmi20/dw_mc.h | 17 +- bsp/drivers/drm/sunxi_device/sunxi_edp.c | 317 +++++++++++++++--- bsp/drivers/drm/sunxi_device/sunxi_edp.h | 62 ++-- bsp/drivers/drm/sunxi_device/sunxi_edp_hdcp.c | 27 ++ bsp/drivers/drm/sunxi_device/sunxi_hdmi.c | 68 +++- bsp/drivers/drm/sunxi_device/sunxi_hdmi.h | 16 + bsp/drivers/drm/sunxi_device/sunxi_tcon.c | 13 +- bsp/drivers/drm/sunxi_drm_drv.c | 61 +++- bsp/drivers/drm/sunxi_drm_edp.c | 83 +++++ bsp/drivers/drm/sunxi_drm_hdmi.c | 11 +- bsp/drivers/gpu/panfrost/panfrost_drv.c | 14 +- bsp/drivers/net/wireless/Kconfig | 12 +- bsp/drivers/net/wireless/Makefile | 11 + .../allwinner/gc_vip_kernel_drv_platform.c | 2 +- bsp/drivers/pinctrl/pinctrl-sun55iw3-r.c | 5 +- bsp/drivers/pinctrl/pinctrl-sunxi.c | 191 ++++++++++- bsp/drivers/pinctrl/pinctrl-sunxi.h | 1 + bsp/drivers/power/Kconfig | 11 + .../power/regulator/axp2101-regulator.c | 95 +++++- .../power/regulator/pmu-ext-regulator.c | 243 +++++++++++++- bsp/drivers/power/supply/axp2202_usb_power.c | 4 + bsp/drivers/sound/platform/Kconfig | 7 +- bsp/drivers/sound/platform/Makefile | 4 + .../sound/platform/snd_sunxi_codec_av.c | 273 +++++++++++++++ bsp/drivers/sound/platform/snd_sunxi_mach.c | 19 +- .../sound/platform/snd_sunxi_mach_utils.c | 39 +++ .../sound/platform/snd_sunxi_mach_utils.h | 2 + .../video/sunxi/disp2/disp/de/include.h | 2 +- .../video/sunxi/disp2/disp/fb_g2d_rot.h | 2 +- bsp/drivers/video/sunxi/disp2/disp/fb_top.h | 2 +- .../video/sunxi/disp2/disp/pq/drv_pq.c | 2 +- .../video/sunxi/disp2/edp/drv_edp_common.h | 2 +- bsp/drivers/video/sunxi/disp2/edp2/drv_edp2.h | 2 +- .../sunxi/disp2/edp2/edp_core/edp_core.h | 2 +- .../disp2/hdmi2/aw_hdmi_core/aw_hdmi_core.h | 2 +- 54 files changed, 2491 insertions(+), 529 deletions(-) create mode 100644 bsp/drivers/andes_adaptor/Kconfig create mode 100644 bsp/drivers/andes_adaptor/Makefile create mode 100644 bsp/drivers/andes_adaptor/cma_non_cacher.c create mode 100644 bsp/drivers/andes_adaptor/dma_ops_adapter.c create mode 100644 bsp/drivers/sound/platform/snd_sunxi_codec_av.c diff --git a/bsp/.gitignore b/bsp/.gitignore index 2a3eb3f1f1..3907c6a98c 100644 --- a/bsp/.gitignore +++ b/bsp/.gitignore @@ -14,3 +14,4 @@ Module.symvers *.ko.cmd *.elf .vscode* +sunxi-autogen.h diff --git a/bsp/drivers/Kconfig b/bsp/drivers/Kconfig index 8cf6039a41..beccf1aebd 100644 --- a/bsp/drivers/Kconfig +++ b/bsp/drivers/Kconfig @@ -109,6 +109,9 @@ source "bsp/drivers/pstore/Kconfig" # FS source "bsp/drivers/fs/Kconfig" +#andes adaptor +source "bsp/drivers/andes_adaptor/Kconfig" + #awlink source "bsp/drivers/awlink/Kconfig" diff --git a/bsp/drivers/Makefile b/bsp/drivers/Makefile index f7b242eade..2a051fafa3 100644 --- a/bsp/drivers/Makefile +++ b/bsp/drivers/Makefile @@ -106,5 +106,8 @@ obj-y += pstore/ # FS obj-y += fs/ +obj-y += andes_adaptor/ + #awlink obj-y += awlink/ + diff --git a/bsp/drivers/andes_adaptor/Kconfig b/bsp/drivers/andes_adaptor/Kconfig new file mode 100644 index 0000000000..047b3e4f0c --- /dev/null +++ b/bsp/drivers/andes_adaptor/Kconfig @@ -0,0 +1,42 @@ +# SPDX-License-Identifier: GPL-2.0-only +# Generic Trusted Execution Environment Configuration + +menu "AW andes adaption" + +config AW_ANDES_DMA_ADAPT + bool "andes dma adapter" + +if AW_ANDES_DMA_ADAPT + +choice + prompt "adapter type" + default AW_ANDES_DMA_OPS + +config AW_ANDES_NO_DIRECT_DMA + bool "direct dma api" + #prohibit default non-cache alloc + select ARCH_HAS_UNCACHED_SEGMENT + select ARCH_HAS_DMA_COHERENT_TO_PFN + +config AW_ANDES_DMA_OPS + bool "overwrite dma ops" + depends on DMA_CMA + help + "overwrite default andes dummy dma ops for drivers" + + +endchoice +endif + +config AW_ANDES_CMA_NON_CACHE + depends on AW_BSP + depends on PMA + depends on DMA_CMA + bool "set cma memory non_cache for devices" + default n + help + This help non-cache memory using with andes platform + +endmenu + + diff --git a/bsp/drivers/andes_adaptor/Makefile b/bsp/drivers/andes_adaptor/Makefile new file mode 100644 index 0000000000..00705bca2c --- /dev/null +++ b/bsp/drivers/andes_adaptor/Makefile @@ -0,0 +1,7 @@ +# SPDX-License-Identifier: GPL-2.0 +# +# Makefile for the drm heap drivers. +# + +obj-$(CONFIG_AW_ANDES_CMA_NON_CACHE) += cma_non_cacher.o +obj-$(CONFIG_AW_ANDES_DMA_ADAPT) += dma_ops_adapter.o diff --git a/bsp/drivers/andes_adaptor/cma_non_cacher.c b/bsp/drivers/andes_adaptor/cma_non_cacher.c new file mode 100644 index 0000000000..72705f3aaf --- /dev/null +++ b/bsp/drivers/andes_adaptor/cma_non_cacher.c @@ -0,0 +1,110 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2023 - 2025 Allwinner Technology Co.,Ltd. All rights reserved. */ +/* + * turn cma buffer non cache to reduce pma usage + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +struct mem_region { + uint64_t startAddr; + uint64_t size; + void *addr; +}; +#define PMA_REGIONS 16 +#define MAX_REGION_SIZE ((uint64_t)4 * 1024 * 1024 * 1024) +__maybe_unused static void generate_mem_map(uint64_t start_addr, uint64_t size, + struct mem_region *map_head, + int region_array_size) +{ + uint64_t thisRegionSize; + int i; + for (i = 0; i < region_array_size; i++) { + thisRegionSize = MAX_REGION_SIZE; + /*use as less regions as possible*/ + while (thisRegionSize > 32 * 1024) { + if ((thisRegionSize <= size) && + /*start addr must at multiple of region size*/ + ((start_addr & (thisRegionSize - 1)) == 0)) + break; + thisRegionSize >>= 1; + } + map_head->startAddr = start_addr; + map_head->size = thisRegionSize; + map_head++; + + start_addr += thisRegionSize; + if (size >= thisRegionSize) { + size -= thisRegionSize; + } else { + pr_err("non-cache no align, extra 0x%llx byte count in region!", + thisRegionSize - size); + size = 0; + } + + if (size == 0) { + break; + } + } + if (size) { + pr_err("Not enough regions, 0x%llx byte ta ram left untouched", + size); + } +} + +__maybe_unused static int set_default_cma_non_cache(void) +{ + struct cma *default_cma = dev_get_cma_area(NULL); + int ret = 0; + unsigned long size; + phys_addr_t base; + struct mem_region regions[PMA_REGIONS]; + int i; + + if (!default_cma) { + pr_err("default cma not found"); + return -ENOMEM; + } + + size = cma_get_size(default_cma); + base = cma_get_base(default_cma); + memset(regions, 0, sizeof(regions)); + generate_mem_map(base, size, regions, ARRAY_SIZE(regions)); + for (i = 0; i < PMA_REGIONS; i++) { + if (regions[i].size == 0) + break; /*early exit*/ + regions[i].addr = ioremap_nocache(base, size); + if (!regions[i].addr) { + pr_err("failed to %llx~%llx in cma %s non-cache", + regions[i].startAddr, + regions[i].startAddr + regions[i].size, + cma_get_name(default_cma)); + } else { + pr_err("base:%pad, size:%lx in cma set non-cache", + &base, size); + /* + * disable movable page so programs dont accidently get + * cma memory and have performance impact + */ + page_group_by_mobility_disabled = 1; + } + } + + return ret; +} + + +arch_initcall(set_default_cma_non_cache); +MODULE_DESCRIPTION("cma buffer non-cacher"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("ouyangkun "); +MODULE_VERSION("1.0.0"); diff --git a/bsp/drivers/andes_adaptor/dma_ops_adapter.c b/bsp/drivers/andes_adaptor/dma_ops_adapter.c new file mode 100644 index 0000000000..5c1aa160e7 --- /dev/null +++ b/bsp/drivers/andes_adaptor/dma_ops_adapter.c @@ -0,0 +1,245 @@ +// SPDX-License-Identifier: GPL-2.0 +/* Copyright(c) 2023 - 2025 Allwinner Technology Co.,Ltd. All rights reserved. */ +/* + * port dma ops to andes platform for memory access + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if IS_ENABLED(CONFIG_AW_ANDES_NO_DIRECT_DMA) +void *uncached_kernel_address(void *ptr) +{ + static phys_addr_t base; + static size_t size; + struct cma *default_cma = dev_get_cma_area(NULL); + + /* oneshot iniliztion */ + if (default_cma) { + size = cma_get_size(default_cma); + base = cma_get_base(default_cma); + } + /* ptr validation */ + if (!size) { + if (base < (phys_addr_t)ptr && (phys_addr_t)ptr < base + size) { + goto ptr_is_uncached; + } + } + pr_err("ptr %pad not non-cached!", &ptr); + dump_stack(); +ptr_is_uncached: + return ptr; +} + +void *cached_kernel_address(void *ptr) +{ + return ptr; +} + +void arch_dma_prep_coherent(struct page *page, size_t size) +{ + arch_sync_dma_for_device(NULL, page_to_phys(page), size, DMA_TO_DEVICE); +} + +long arch_dma_coherent_to_pfn(struct device *dev, void *cpu_addr, + dma_addr_t dma_addr) +{ + return __phys_to_pfn(dma_to_phys(dev, dma_addr)); +} +#endif + +#if IS_ENABLED(CONFIG_AW_ANDES_DMA_OPS) + +/* + * presumption: + * 1. no-iommu involved so all memory we are dealing with + * is contiguous here + * 2. we are working on an platform works with limited dram + * so highmem no need to worry about, lowmem address space + * covers all the dram we have + */ +static void *nommu_dma_alloc(struct device *dev, size_t size, + dma_addr_t *dma_handle, gfp_t gfp, + unsigned long attrs) + +{ + unsigned long order = get_order(size); + size_t count = ALIGN(size, PAGE_SIZE) >> PAGE_SHIFT; + struct page *page; + void *ptr = NULL; + + page = dma_alloc_from_contiguous(dev, count, order, gfp & __GFP_NOWARN); + if (!page) + return NULL; + + ptr = page_address(page); + *dma_handle = page_to_phys(page); + + return ptr; +} + +static void nommu_dma_free(struct device *dev, size_t size, void *cpu_addr, + dma_addr_t dma_addr, unsigned long attrs) +{ + int ret ; + ret = dma_release_from_contiguous(dev, phys_to_page(dma_addr), + PAGE_ALIGN(size) >> PAGE_SHIFT); + /* cma release return false for error, true for ok */ + WARN_ON_ONCE(ret == false); +} + +static int check_dma_addr(struct device *dev, dma_addr_t dma_addr, size_t size) +{ + struct cma *cma_area; + phys_addr_t dma_start, dma_end; + phys_addr_t cma_start, cma_end; + cma_area = dev_get_cma_area(dev); + cma_start = cma_get_base(cma_area); + cma_end = cma_start + cma_get_size(cma_area); + dma_start = dma_addr; + dma_end = dma_addr + size; + if ((dma_addr < cma_start) || (dma_end > cma_end)) { + pr_err("dma addr %pad ~ %pad not in cam area %pad ~ %pad", + &dma_addr, &dma_end, &cma_start, &cma_end); + dump_stack(); + return -1; + } + return 0; +} + +static int nommu_dma_mmap(struct device *dev, struct vm_area_struct *vma, + void *cpu_addr, dma_addr_t dma_addr, size_t size, + unsigned long attrs) +{ + int ret; + /* param sanity check */ + check_dma_addr(dev, dma_addr, size); + + ret = remap_pfn_range(vma, vma->vm_start, phys_to_pfn(dma_addr), size, + vma->vm_page_prot); + + return ret; +} + +static void __dma_page_cpu_to_dev(phys_addr_t paddr, size_t size, + enum dma_data_direction dir) +{ + arch_sync_dma_for_device(NULL, paddr, size, dir); +} + +static void __dma_page_dev_to_cpu(phys_addr_t paddr, size_t size, + enum dma_data_direction dir) +{ + arch_sync_dma_for_cpu(NULL, paddr, size, dir); +} + +static dma_addr_t nommu_dma_map_page(struct device *dev, struct page *page, + unsigned long offset, size_t size, + enum dma_data_direction dir, + unsigned long attrs) +{ + dma_addr_t handle = page_to_phys(page) + offset; + check_dma_addr(dev, handle, size); + + __dma_page_cpu_to_dev(handle, size, dir); + + return handle; +} + +static void nommu_dma_unmap_page(struct device *dev, dma_addr_t handle, + size_t size, enum dma_data_direction dir, + unsigned long attrs) +{ + __dma_page_dev_to_cpu(handle, size, dir); +} + +static int nommu_dma_map_sg(struct device *dev, struct scatterlist *sgl, + int nents, enum dma_data_direction dir, + unsigned long attrs) +{ + int i; + struct scatterlist *sg; + + for_each_sg (sgl, sg, nents, i) { + sg_dma_address(sg) = sg_phys(sg); + sg_dma_len(sg) = sg->length; + __dma_page_cpu_to_dev(sg_dma_address(sg), sg_dma_len(sg), dir); + } + + return nents; +} + +static void nommu_dma_unmap_sg(struct device *dev, struct scatterlist *sgl, + int nents, enum dma_data_direction dir, + unsigned long attrs) +{ + struct scatterlist *sg; + int i; + + for_each_sg (sgl, sg, nents, i) + __dma_page_dev_to_cpu(sg_dma_address(sg), sg_dma_len(sg), dir); +} + +static void nommu_dma_sync_single_for_device(struct device *dev, + dma_addr_t handle, size_t size, + enum dma_data_direction dir) +{ + __dma_page_cpu_to_dev(handle, size, dir); +} + +static void nommu_dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle, + size_t size, + enum dma_data_direction dir) +{ + __dma_page_cpu_to_dev(handle, size, dir); +} + +static void nommu_dma_sync_sg_for_device(struct device *dev, + struct scatterlist *sgl, int nents, + enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg (sgl, sg, nents, i) + __dma_page_cpu_to_dev(sg_dma_address(sg), sg_dma_len(sg), dir); +} + +static void nommu_dma_sync_sg_for_cpu(struct device *dev, + struct scatterlist *sgl, int nents, + enum dma_data_direction dir) +{ + struct scatterlist *sg; + int i; + + for_each_sg (sgl, sg, nents, i) + __dma_page_dev_to_cpu(sg_dma_address(sg), sg_dma_len(sg), dir); +} + +const struct dma_map_ops aw_andes_dma_ops = { + .alloc = nommu_dma_alloc, + .free = nommu_dma_free, + .mmap = nommu_dma_mmap, + .map_page = nommu_dma_map_page, + .unmap_page = nommu_dma_unmap_page, + .map_sg = nommu_dma_map_sg, + .unmap_sg = nommu_dma_unmap_sg, + .sync_single_for_device = nommu_dma_sync_single_for_device, + .sync_single_for_cpu = nommu_dma_sync_single_for_cpu, + .sync_sg_for_device = nommu_dma_sync_sg_for_device, + .sync_sg_for_cpu = nommu_dma_sync_sg_for_cpu, +}; +EXPORT_SYMBOL(aw_andes_dma_ops); +#endif + +MODULE_DESCRIPTION("dma ops adapter"); +MODULE_LICENSE("GPL v2"); +MODULE_AUTHOR("ouyangkun "); +MODULE_VERSION("1.0.0"); \ No newline at end of file diff --git a/bsp/drivers/dma/sunxi-dma.c b/bsp/drivers/dma/sunxi-dma.c index f3e8c058cb..480212888e 100644 --- a/bsp/drivers/dma/sunxi-dma.c +++ b/bsp/drivers/dma/sunxi-dma.c @@ -23,7 +23,7 @@ #include #include "sunxi-dma.h" -#define SUNXI_DMA_MODULE_VERSION "1.0.12" +#define SUNXI_DMA_MODULE_VERSION "1.0.13" /* * Common registers */ @@ -1118,6 +1118,7 @@ static int sun6i_dma_pause(struct dma_chan *chan) struct sun6i_dma_dev *sdev = to_sun6i_dma_dev(chan->device); struct sun6i_vchan *vchan = to_sun6i_vchan(chan); struct sun6i_pchan *pchan = vchan->phy; + unsigned long flags; dev_dbg(chan2dev(chan), "vchan %p: pause\n", &vchan->vc); @@ -1125,9 +1126,9 @@ static int sun6i_dma_pause(struct dma_chan *chan) writel(DMA_CHAN_PAUSE_PAUSE, pchan->base + DMA_CHAN_PAUSE); } else { - spin_lock(&sdev->lock); + spin_lock_irqsave(&sdev->lock, flags); list_del_init(&vchan->node); - spin_unlock(&sdev->lock); + spin_unlock_irqrestore(&sdev->lock, flags); } return 0; @@ -1166,9 +1167,9 @@ static int sun6i_dma_terminate_all(struct dma_chan *chan) unsigned long flags; LIST_HEAD(head); - spin_lock(&sdev->lock); + spin_lock_irqsave(&sdev->lock, flags); list_del_init(&vchan->node); - spin_unlock(&sdev->lock); + spin_unlock_irqrestore(&sdev->lock, flags); spin_lock_irqsave(&vchan->vc.lock, flags); diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_edp/inno_edp13/inno_edp13.c b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_edp/inno_edp13/inno_edp13.c index 442fde7182..dd863b8cef 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_edp/inno_edp13/inno_edp13.c +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_edp/inno_edp13/inno_edp13.c @@ -1697,6 +1697,23 @@ s32 inno_audio_disable(struct sunxi_edp_hw_desc *edp_hw) return RET_OK; } +s32 inno_audio_config(struct sunxi_edp_hw_desc *edp_hw, int interface, + int chn_cnt, int data_width, int data_rate) +{ + edp_audio_interface_config(edp_hw, interface); + edp_audio_channel_config(edp_hw, chn_cnt); + edp_audio_data_width_config(edp_hw, data_width); + + return RET_OK; +} + +s32 inno_audio_mute(struct sunxi_edp_hw_desc *edp_hw, bool enable, int direction) +{ + edp_audio_mute_config(edp_hw, enable); + + return RET_OK; +} + /* s32 edp_hal_audio_set_para(edp_audio_t *para) @@ -2082,7 +2099,7 @@ bool inno13_audio_is_enabled(struct sunxi_edp_hw_desc *edp_hw) return false; } -s32 inno_get_audio_if(struct sunxi_edp_hw_desc *edp_hw) +u32 inno_get_audio_if(struct sunxi_edp_hw_desc *edp_hw) { u32 reg_val; @@ -2092,17 +2109,22 @@ s32 inno_get_audio_if(struct sunxi_edp_hw_desc *edp_hw) return reg_val; } -s32 inno_audio_is_muted(struct sunxi_edp_hw_desc *edp_hw) +bool inno_audio_is_muted(struct sunxi_edp_hw_desc *edp_hw) { u32 reg_val; reg_val = readl(edp_hw->reg_base + REG_EDP_AUDIO); reg_val = GET_BITS(15, 1, reg_val); - return reg_val; + return reg_val ? true : false; } -s32 inno_get_audio_chn_cnt(struct sunxi_edp_hw_desc *edp_hw) +u32 inno_get_audio_max_channel(struct sunxi_edp_hw_desc *edp_hw) +{ + return 8; +} + +u32 inno_get_audio_chn_cnt(struct sunxi_edp_hw_desc *edp_hw) { u32 reg_val; @@ -2117,7 +2139,7 @@ s32 inno_get_audio_chn_cnt(struct sunxi_edp_hw_desc *edp_hw) return 8; } -s32 inno_get_audio_date_width(struct sunxi_edp_hw_desc *edp_hw) +u32 inno_get_audio_date_width(struct sunxi_edp_hw_desc *edp_hw) { u32 reg_val; @@ -2318,6 +2340,27 @@ bool inno_check_controller_error(struct sunxi_edp_hw_desc *edp_hw) return false; } +void inno_enhance_frame_enable(struct sunxi_edp_hw_desc *edp_hw, bool enable) +{ + u32 reg_val; + + if (enable) { + reg_val = readl(edp_hw->reg_base + REG_EDP_HPD_SCALE); + reg_val = SET_BITS(1, 1, reg_val, 1); + writel(reg_val, edp_hw->reg_base + REG_EDP_HPD_SCALE); + } else { + reg_val = readl(edp_hw->reg_base + REG_EDP_HPD_SCALE); + reg_val = SET_BITS(1, 1, reg_val, 0); + writel(reg_val, edp_hw->reg_base + REG_EDP_HPD_SCALE); + } +} + +bool inno_support_enhance_frame(struct sunxi_edp_hw_desc *edp_hw) +{ + return true; +} + + static struct sunxi_edp_hw_video_ops inno_edp13_video_ops = { .check_controller_error = inno_check_controller_error, .assr_enable = inno_assr_enable, @@ -2330,14 +2373,7 @@ static struct sunxi_edp_hw_video_ops inno_edp13_video_ops = { .get_tu_valid_symbol = inno_get_tu_valid_symbol, .get_hotplug_change = inno_get_hotplug_change, .get_hotplug_state = inno_get_hotplug_state, - .audio_is_enabled = inno13_audio_is_enabled, - .get_audio_if = inno_get_audio_if, - .audio_is_muted = inno_audio_is_muted, - .audio_enable = inno_audio_enable, - .audio_disable = inno_audio_disable, .get_pattern = inno_get_pattern, - .get_audio_data_width = inno_get_audio_date_width, - .get_audio_chn_cnt = inno_get_audio_chn_cnt, .set_pattern = inno_set_pattern, .ssc_enable = inno_ssc_enable, .ssc_is_enabled = inno_ssc_is_enabled, @@ -2369,17 +2405,14 @@ static struct sunxi_edp_hw_video_ops inno_edp13_video_ops = { .support_max_lane = inno_get_max_lane, .support_tps3 = inno_support_tps3, .support_fast_training = inno_support_fast_train, - .support_audio = inno_support_audio, .support_psr = inno_support_psr, .support_psr2 = inno_support_psr2, .support_ssc = inno_support_ssc, .support_mst = inno_support_mst, .support_fec = inno_support_fec, .support_assr = inno_support_assr, - .support_hdcp1x = inno_support_hdcp1x, - .support_hdcp2x = inno_support_hdcp2x, - .support_hw_hdcp1x = inno_support_hw_hdcp1x, - .support_hw_hdcp2x = inno_support_hw_hdcp2x, + .enhance_frame_enable = inno_enhance_frame_enable, + .support_enhance_frame = inno_support_enhance_frame, }; struct sunxi_edp_hw_video_ops *sunxi_edp_get_hw_video_ops(void) @@ -2387,3 +2420,21 @@ struct sunxi_edp_hw_video_ops *sunxi_edp_get_hw_video_ops(void) return &inno_edp13_video_ops; } +static struct sunxi_edp_hw_audio_ops inno_edp13_audio_ops = { + .support_audio = inno_support_audio, + .audio_is_enabled = inno13_audio_is_enabled, + .get_audio_if = inno_get_audio_if, + .audio_is_muted = inno_audio_is_muted, + .audio_enable = inno_audio_enable, + .audio_disable = inno_audio_disable, + .audio_mute = inno_audio_mute, + .audio_config = inno_audio_config, + .get_audio_data_width = inno_get_audio_date_width, + .get_audio_chn_cnt = inno_get_audio_chn_cnt, + .get_audio_max_channel = inno_get_audio_max_channel, +}; + +struct sunxi_edp_hw_audio_ops *sunxi_edp_get_hw_audio_ops(void) +{ + return &inno_edp13_audio_ops; +} \ No newline at end of file diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_edp/trilinear_dp14/trilinear_dp14.c b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_edp/trilinear_dp14/trilinear_dp14.c index 7f31a6b8f9..fcdac5926a 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_edp/trilinear_dp14/trilinear_dp14.c +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_edp/trilinear_dp14/trilinear_dp14.c @@ -28,6 +28,61 @@ struct edp_aux_request { int data[16]; }; +struct edp_audio_mn_aud { + int link_bw; + int data_rate; + int maud; + int naud; +}; + +#define EDP_AUD_DEFINE(bw, rate, m, n) \ + .link_bw = bw, \ + .data_rate = rate, \ + .maud = m, \ + .naud = n, + +struct edp_audio_mn_aud aud_tbl[] = { + { EDP_AUD_DEFINE(162, 32000, 1024, 10125) }, + { EDP_AUD_DEFINE(162, 44100, 784, 5625) }, + { EDP_AUD_DEFINE(162, 48000, 512, 3375) }, + { EDP_AUD_DEFINE(162, 64000, 2048, 10125) }, + { EDP_AUD_DEFINE(162, 88200, 1568, 5625) }, + { EDP_AUD_DEFINE(162, 90600, 1024, 3375) }, + { EDP_AUD_DEFINE(162, 128000, 4096, 10125) }, + { EDP_AUD_DEFINE(162, 176400, 3136, 5625) }, + { EDP_AUD_DEFINE(162, 192000, 2048, 3375) }, + + { EDP_AUD_DEFINE(270, 32000, 1024, 16875) }, + { EDP_AUD_DEFINE(270, 44100, 784, 9375) }, + { EDP_AUD_DEFINE(270, 48000, 512, 5625) }, + { EDP_AUD_DEFINE(270, 64000, 2048, 16875) }, + { EDP_AUD_DEFINE(270, 88200, 1568, 9375) }, + { EDP_AUD_DEFINE(270, 90600, 1024, 5625) }, + { EDP_AUD_DEFINE(270, 128000, 4096, 16875) }, + { EDP_AUD_DEFINE(270, 176400, 3136, 9375) }, + { EDP_AUD_DEFINE(270, 192000, 2048, 5625) }, + + { EDP_AUD_DEFINE(540, 32000, 1024, 33750) }, + { EDP_AUD_DEFINE(540, 44100, 784, 18750) }, + { EDP_AUD_DEFINE(540, 48000, 512, 11250) }, + { EDP_AUD_DEFINE(540, 64000, 2048, 33750) }, + { EDP_AUD_DEFINE(540, 88200, 1568, 18750) }, + { EDP_AUD_DEFINE(540, 90600, 1024, 11250) }, + { EDP_AUD_DEFINE(540, 128000, 4096, 33750) }, + { EDP_AUD_DEFINE(540, 176400, 3136, 18750) }, + { EDP_AUD_DEFINE(540, 192000, 2048, 11250) }, + + { EDP_AUD_DEFINE(810, 32000, 1024, 50625) }, + { EDP_AUD_DEFINE(810, 44100, 784, 28125) }, + { EDP_AUD_DEFINE(810, 48000, 512, 16875) }, + { EDP_AUD_DEFINE(810, 64000, 2048, 50625) }, + { EDP_AUD_DEFINE(810, 88200, 1568, 28125) }, + { EDP_AUD_DEFINE(810, 90600, 1024, 16875) }, + { EDP_AUD_DEFINE(810, 128000, 4096, 50625) }, + { EDP_AUD_DEFINE(810, 176400, 3136, 28125) }, + { EDP_AUD_DEFINE(810, 192000, 2048, 16875) }, +}; + u32 TR_READ(struct sunxi_edp_hw_desc *edp_hw, u32 addr) { return readl(edp_hw->reg_base + addr); @@ -754,38 +809,155 @@ void trilinear_dsc_enable(struct sunxi_edp_hw_desc *edp_hw, bool enable) TR_SET_BITS(edp_hw, TR_DSC_COMPRESSION_EN, 0, 1, 0x0); } +static void trilinear_audio_set_interface(struct sunxi_edp_hw_desc *edp_hw, int interface) +{ + switch (interface) { + case HDMI_SPDIF: + TR_SET_BITS(edp_hw, TR_SEC0_AUDIO_INPUT_SEL, 0, 2, 0x3); + break; + default: + case HDMI_I2S: + TR_SET_BITS(edp_hw, TR_SEC0_AUDIO_INPUT_SEL, 0, 2, 0x0); + break; + } +} + +static void trilinear_audio_set_channel_cnt(struct sunxi_edp_hw_desc *edp_hw, int chn_cnt) +{ + switch (chn_cnt) { + case 2: + TR_SET_BITS(edp_hw, TR_SEC0_CHANNEL_CNT, 0, 32, 0x2); + break; + case 5: + TR_SET_BITS(edp_hw, TR_SEC0_CHANNEL_CNT, 0, 32, 0x6); + break; + default: + case 8: + TR_SET_BITS(edp_hw, TR_SEC0_CHANNEL_CNT, 0, 32, 0x8); + break; + } + +} + +static void trilinear_audio_set_mn_aud(struct sunxi_edp_hw_desc *edp_hw, + int link_bw, int audio_data_rate) +{ + int i = 0; + + for (i = 0; i < ARRAY_SIZE(aud_tbl); i++) { + if ((aud_tbl[i].link_bw == link_bw) && + (aud_tbl[i].data_rate == audio_data_rate)) { + TR_SET_BITS(edp_hw, TR_SEC0_MAUD, 0, 32, aud_tbl[i].maud); + TR_SET_BITS(edp_hw, TR_SEC0_NAUD, 0, 32, aud_tbl[i].naud); + break; + } + } +} + +static void trilinear_audio_set_data_rate(struct sunxi_edp_hw_desc *edp_hw, int audio_data_rate) +{ + int link_bw = 0; + + link_bw = TR_READ(edp_hw, TR_LINK_BW_SET) * 27; + + /* set audio clock mode to synchronous mode */ + TR_SET_BITS(edp_hw, TR_SEC0_AUDIO_CLOCK_MODE, 0, 32, 0x1); + + /* set MAUD NAUD */ + trilinear_audio_set_mn_aud(edp_hw, link_bw, audio_data_rate); +} + s32 trilinear_audio_enable(struct sunxi_edp_hw_desc *edp_hw) { + TR_SET_BITS(edp_hw, TR_SEC0_AUDIO_ENABLE, 0, 1, 0x1); + return RET_OK; } s32 trilinear_audio_disable(struct sunxi_edp_hw_desc *edp_hw) { + TR_SET_BITS(edp_hw, TR_SEC0_AUDIO_ENABLE, 0, 1, 0x0); + return RET_OK; } -bool trilinear_audio_is_enabled(struct sunxi_edp_hw_desc *edp_hw) +s32 trilinear_audio_mute(struct sunxi_edp_hw_desc *edp_hw, + bool enable, int direction) { - return false; + TR_SET_BITS(edp_hw, TR_SEC0_AUDIO_ENABLE, 1, 1, enable ? 0x1 : 0x0); + + return RET_OK; } -s32 trilinear_get_audio_if(struct sunxi_edp_hw_desc *edp_hw) +s32 trilinear_audio_config(struct sunxi_edp_hw_desc *edp_hw, int interface, + int chn_cnt, int data_width, int data_rate) { + trilinear_audio_set_interface(edp_hw, interface); + trilinear_audio_set_channel_cnt(edp_hw, chn_cnt); + trilinear_audio_set_data_rate(edp_hw, data_rate); +// trilinear_audio_set_data_width(edp_hw, data_width); return RET_OK; } -s32 trilinear_audio_is_muted(struct sunxi_edp_hw_desc *edp_hw) +bool trilinear_audio_is_enabled(struct sunxi_edp_hw_desc *edp_hw) { - return RET_OK; + int reg_val = 0; + + reg_val = TR_GET_BITS(edp_hw, TR_SEC0_AUDIO_ENABLE, 0, 1); + + return reg_val ? true : false; } -s32 trilinear_get_audio_chn_cnt(struct sunxi_edp_hw_desc *edp_hw) +u32 trilinear_get_audio_if(struct sunxi_edp_hw_desc *edp_hw) { - //TODO + int reg_val = 0; + + reg_val = TR_GET_BITS(edp_hw, TR_SEC0_AUDIO_INPUT_SEL, 0, 2); + + switch (reg_val) { + case 0x3: + return 0; + default: + case 0x0: + return 1; + } + + return 1; +} + +bool trilinear_audio_is_muted(struct sunxi_edp_hw_desc *edp_hw) +{ + int reg_val = 0; + + reg_val = TR_GET_BITS(edp_hw, TR_SEC0_AUDIO_ENABLE, 1, 1); + + return reg_val ? true : false; +} + +u32 trilinear_get_audio_max_channel(struct sunxi_edp_hw_desc *edp_hw) +{ + return 8; +} + +u32 trilinear_get_audio_chn_cnt(struct sunxi_edp_hw_desc *edp_hw) +{ + int reg_val = 0; + + reg_val = TR_GET_BITS(edp_hw, TR_SEC0_CHANNEL_CNT, 0, 32); + + switch (reg_val) { + case 2: + return 2; + case 6: + return 5; + case 8: + return 8; + } + return 0; } -s32 trilinear_get_audio_date_width(struct sunxi_edp_hw_desc *edp_hw) +u32 trilinear_get_audio_date_width(struct sunxi_edp_hw_desc *edp_hw) { //TODO return 0; @@ -1537,15 +1709,8 @@ static struct sunxi_edp_hw_video_ops trilinear_dp14_video_ops = { .get_hotplug_change = trilinear_get_hotplug_change, .get_hotplug_state = trilinear_get_hotplug_state, .irq_handle = trilinear_irq_handler, - .audio_is_enabled = trilinear_audio_is_enabled, - .get_audio_if = trilinear_get_audio_if, - .audio_is_muted = trilinear_audio_is_muted, - .audio_enable = trilinear_audio_enable, - .audio_disable = trilinear_audio_disable, .get_pattern = trilinear_get_pattern, .set_pattern = trilinear_set_pattern, - .get_audio_data_width = trilinear_get_audio_date_width, - .get_audio_chn_cnt = trilinear_get_audio_chn_cnt, .aux_read = trilinear_aux_read, .aux_write = trilinear_aux_write, .aux_i2c_read = trilinear_aux_i2c_read, @@ -1575,17 +1740,12 @@ static struct sunxi_edp_hw_video_ops trilinear_dp14_video_ops = { .support_max_lane = trilinear_get_max_lane, .support_tps3 = trilinear_support_tps3, .support_fast_training = trilinear_support_fast_train, - .support_audio = trilinear_support_audio, .support_psr = trilinear_support_psr, .support_psr2 = trilinear_support_psr2, .support_ssc = trilinear_support_ssc, .support_mst = trilinear_support_mst, .support_fec = trilinear_support_fec, .support_assr = trilinear_support_assr, - .support_hdcp1x = trilinear_support_hdcp1x, - .support_hdcp2x = trilinear_support_hdcp2x, - .support_hw_hdcp1x = trilinear_support_hardware_hdcp1x, - .support_hw_hdcp2x = trilinear_support_hardware_hdcp2x, .support_lane_remap = trilinear_support_lane_remap, .support_lane_invert = trilinear_support_lane_invert, .support_enhance_frame = trilinear_support_enhance_frame, @@ -1596,7 +1756,24 @@ struct sunxi_edp_hw_video_ops *sunxi_edp_get_hw_video_ops(void) return &trilinear_dp14_video_ops; } +static struct sunxi_edp_hw_audio_ops trilinear_dp14_audio_ops = { + .support_audio = trilinear_support_audio, + .audio_enable = trilinear_audio_enable, + .audio_disable = trilinear_audio_disable, + .audio_config = trilinear_audio_config, + .audio_mute = trilinear_audio_mute, + .audio_is_enabled = trilinear_audio_is_enabled, + .get_audio_if = trilinear_get_audio_if, + .audio_is_muted = trilinear_audio_is_muted, + .get_audio_data_width = trilinear_get_audio_date_width, + .get_audio_chn_cnt = trilinear_get_audio_chn_cnt, + .get_audio_max_channel = trilinear_get_audio_max_channel, +}; +struct sunxi_edp_hw_audio_ops *sunxi_edp_get_hw_audio_ops(void) +{ + return &trilinear_dp14_audio_ops; +} void trilinear_hdcp_set_mode(struct sunxi_edp_hw_desc *edp_hw, enum dp_hdcp_mode mode) @@ -1713,6 +1890,10 @@ u64 trilinear_hdcp1_get_m0(struct sunxi_edp_hw_desc *edp_hw) } struct sunxi_edp_hw_hdcp_ops trilinear_dp14_dpcd_ops = { + .support_hdcp1x = trilinear_support_hdcp1x, + .support_hdcp2x = trilinear_support_hdcp2x, + .support_hw_hdcp1x = trilinear_support_hardware_hdcp1x, + .support_hw_hdcp2x = trilinear_support_hardware_hdcp2x, .hdcp1_get_an = trilinear_hdcp1_get_an, .hdcp1_get_aksv = trilinear_hdcp1_get_aksv, .hdcp1_write_bksv = trilinear_hdcp1_write_bksv, diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_avp.c b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_avp.c index f05a9264b6..cfb7b5de5a 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_avp.c +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_avp.c @@ -847,7 +847,7 @@ int dw_audio_on(void) /* Configure audio info frame packets */ dw_fc_audio_packet_config(audio); - dw_mc_disable_audio_sampler_clock(0x0); + dw_mc_set_audio_sample_clk(DW_HDMI_ENABLE); dw_fc_audio_set_mute(0); @@ -1258,7 +1258,7 @@ ssize_t dw_avp_dump(char *buf) int dw_avp_set_mute(u8 enable) { dw_gcp_set_avmute(enable); - dw_hdcp_set_avmute_state(enable); + dw_hdcp1x_set_avmute(enable); return 0; } diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_cec.c b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_cec.c index 24a2c46c42..63031008ab 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_cec.c +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_cec.c @@ -80,7 +80,7 @@ int dw_cec_set_enable(u8 enable) u8 mask = 0x0; if (enable == 0x1) { /* enable cec module clock */ - dw_mc_disable_cec_clock(0x0); + dw_mc_set_cec_clk(DW_HDMI_ENABLE); udelay(20); @@ -122,7 +122,7 @@ int dw_cec_set_enable(u8 enable) udelay(20); /* disable cec module clock */ - dw_mc_disable_cec_clock(0x1); + dw_mc_set_cec_clk(DW_HDMI_DISABLE); } return 0; } diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_dev.c b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_dev.c index ad035d666e..03bdd03fda 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_dev.c +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_dev.c @@ -166,7 +166,7 @@ int dw_hdmi_ctrl_update(void) int dw_hdmi_scdc_set_scramble(u8 setup) { -#if LINUX_VERSION_CODE < KERNEL_VERSION(5, 19, 0) +#if LINUX_VERSION_CODE < KERNEL_VERSION(6, 4, 0) struct i2c_adapter *dev = hdmi->i2c_adap; #else struct drm_connector *dev = hdmi->connect; diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_dev.h b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_dev.h index ca2a6cb820..d915ce8ed6 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_dev.h +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_dev.h @@ -15,6 +15,9 @@ #include #include +#define DW_HDMI_ENABLE (1) +#define DW_HDMI_DISABLE (0) + #define DW_EDID_MAC_HDMI_VIC 16 #define DW_EDID_MAX_HDMI_3DSTRUCT 16 #define DW_EDID_MAX_VIC_WITH_3D 16 @@ -701,6 +704,17 @@ struct dw_hdmi_dev_s { dump_stack(); \ } while (0) +#ifdef shdmi_free_point +#undef shdmi_free_point +#endif +#define shdmi_free_point(x) \ + do { \ + if (x != NULL) { \ + kfree(x); \ + x = NULL; \ + } \ + } while (0) + /** * @desc: get byte from dw index * @data: u32 data diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp.c b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp.c index 9b1a189faa..c3d6b5962e 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp.c +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp.c @@ -38,14 +38,14 @@ static struct dw_hdcp_s *hdcp; #define DW_HDCP14_KSV_LEN (5) #define DW_HDCP14_OESS_SIZE (0x40) -enum _dw_hdcp_state_e { - HDCP_IDLE = 0, - HDCP_KSV_LIST_READY, - HDCP_ERR_KSV_LIST_NOT_VALID, - HDCP_KSV_LIST_ERR_DEPTH_EXCEEDED, - HDCP_KSV_LIST_ERR_MEM_ACCESS, - HDCP_ENGAGED, - HDCP_FAILED +enum _dw_hdcp1x_state_e { + DW_HDCP1X_IDLE = 0, + DW_HDCP1X_KSV_READY, + DW_HDCP1X_KSV_ERR_INVALID, + DW_HDCP1X_KSV_ERR_DEPTH_EXCEEDED, + DW_HDCP1X_KSV_ERR_MEM_ACCESS, + DW_HDCP1X_ENGAGED, + DW_HDCP1X_FAILED }; struct _dw_hdcp14_sha_s{ @@ -57,20 +57,49 @@ struct _dw_hdcp14_sha_s{ unsigned mDigest[5]; } ; -static int _dw_hdcp_get_enable_type(void) +static inline int _dw_hdcp_get_enable_type(void) { return hdcp->enable_type; } -static u8 _dw_hdcp_get_data_path(void) +static inline void _dw_hdcp1x_set_rxdetect(u8 bit) { - int ret = 0x0; + dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_RXDETECT_MASK, bit); +} - if (dw_read_mask(HDCP22REG_CTRL, HDCP22REG_CTRL_HDCP22_OVR_EN_MASK) && - dw_read_mask(HDCP22REG_CTRL, HDCP22REG_CTRL_HDCP22_OVR_VAL_MASK)) - ret = 0x1; +static inline void _dw_hdcp1x_set_encrypt(u8 bit) +{ + dw_write_mask(A_HDCPCFG1, A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, !bit); +} - return ret; +static inline void _dw_hdcp1x_int_clear(u8 value) +{ + dw_write(A_APIINTCLR, value); +} + +static inline void _dw_hdcp1x_int_mask(u8 value) +{ + dw_write(A_APIINTMSK, value); +} + +static inline void _dw_hdcp1x_set_oess_size(u8 value) +{ + dw_write(A_OESSWCFG, value); +} + +static inline void _dw_hdcp1x_set_data_polarity(u8 enable) +{ + dw_write_mask(A_VIDPOLCFG, A_VIDPOLCFG_DATAENPOL_MASK, enable); +} + +static inline u8 _dw_hdcp1x_sha_get_memory_granted(void) +{ + return (u8)dw_read_mask(A_KSVMEMCTRL, A_KSVMEMCTRL_KSVMEMACCESS_MASK); +} + +void dw_hdcp1x_set_avmute(int enable) +{ + dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_AVMUTE_MASK, enable); } int dw_hdcp_set_enable_type(int type) @@ -84,11 +113,6 @@ int dw_hdcp_set_enable_type(int type) return hdcp->enable_type; } -void dw_hdcp_set_avmute_state(int enable) -{ - dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_AVMUTE_MASK, enable); -} - void dw_hdcp_sync_tmds_mode(void) { dw_tmds_mode_t mode = dw_fc_video_get_tmds_mode(); @@ -104,23 +128,7 @@ void dw_hdcp_sync_data_polarity(void) dw_write_mask(A_VIDPOLCFG, A_VIDPOLCFG_VSYNCPOL_MASK, vsPol ? 0x1 : 0x0); dw_write_mask(A_VIDPOLCFG, A_VIDPOLCFG_HSYNCPOL_MASK, hsPol ? 0x1 : 0x0); - dw_write_mask(A_VIDPOLCFG, A_VIDPOLCFG_DATAENPOL_MASK, 0x1); -} - -/** - * @path: 0 - hdcp14 path - * 1 - hdcp22 path - */ -void dw_hdcp_set_data_path(u8 path) -{ - dw_write_mask(HDCP22REG_CTRL, HDCP22REG_CTRL_HDCP22_OVR_VAL_MASK, path); - dw_write_mask(HDCP22REG_CTRL, HDCP22REG_CTRL_HDCP22_OVR_EN_MASK, 0x1); -} - -static u8 _dw_hdcp1x_sha_get_memory_granted(void) -{ - return (u8)((dw_read(A_KSVMEMCTRL) - & A_KSVMEMCTRL_KSVMEMACCESS_MASK) >> 1); + _dw_hdcp1x_set_data_polarity(DW_HDMI_ENABLE); } static void _dw_hdcp1x_sha_reset(struct _dw_hdcp14_sha_s *sha) @@ -319,7 +327,7 @@ static u8 _dw_hdcp1x_sha_calculation(int *param) int timeout = 1000; u16 bstatus = 0; u16 deviceCount = 0; - int valid = HDCP_IDLE; + int valid = DW_HDCP1X_IDLE; int size = 0; int i = 0; @@ -342,7 +350,7 @@ static u8 _dw_hdcp1x_sha_calculation(int *param) dw_write_mask(A_KSVMEMCTRL, A_KSVMEMCTRL_KSVMEMREQUEST_MASK, 0x0); hdcp_log("KSV List memory access denied"); *param = 0; - return HDCP_KSV_LIST_ERR_MEM_ACCESS; + return DW_HDCP1X_KSV_ERR_MEM_ACCESS; } /* 3 - Read VH', M0, Bstatus, and the KSV FIFO. @@ -356,7 +364,7 @@ static u8 _dw_hdcp1x_sha_calculation(int *param) if (deviceCount > DW_HDCP14_MAX_DEVICES) { *param = 0; hdcp_log("depth exceeds KSV List memory"); - return HDCP_KSV_LIST_ERR_DEPTH_EXCEEDED; + return DW_HDCP1X_KSV_ERR_DEPTH_EXCEEDED; } size = deviceCount * DW_HDCP14_KSV_LEN + DW_HDCP14_KSV_HEADER + DW_HDCP14_KSV_SHAMAX; @@ -376,11 +384,11 @@ static u8 _dw_hdcp1x_sha_calculation(int *param) /* 4 - Calculate the SHA-1 checksum (VH) over M0, Bstatus, and the KSV FIFO. */ if (_dw_hdcp1x_sha_verify_ksv(hdcp_ksv_list_buffer, size) == true) { - valid = HDCP_KSV_LIST_READY; - hdcp_log("HDCP_KSV_LIST_READY"); + valid = DW_HDCP1X_KSV_READY; + hdcp_log("dw hdcp1x verify ksv list ready\n"); } else { - valid = HDCP_ERR_KSV_LIST_NOT_VALID; - hdcp_log("HDCP_ERR_KSV_LIST_NOT_VALID"); + valid = DW_HDCP1X_KSV_ERR_INVALID; + hdcp_log("dw hdcp1x verify ksv not valid\n"); } /* 5 - If the calculated VH equals the VH', @@ -392,51 +400,28 @@ static u8 _dw_hdcp1x_sha_calculation(int *param) /* to re-authenticate from the beginning. */ dw_write_mask(A_KSVMEMCTRL, A_KSVMEMCTRL_KSVMEMREQUEST_MASK, 0x0); dw_write_mask(A_KSVMEMCTRL, A_KSVMEMCTRL_SHA1FAIL_MASK, - (valid == HDCP_KSV_LIST_READY) ? 0 : 1); + (valid == DW_HDCP1X_KSV_READY) ? 0 : 1); dw_write_mask(A_KSVMEMCTRL, A_KSVMEMCTRL_KSVCTRLUPD_MASK, 1); dw_write_mask(A_KSVMEMCTRL, A_KSVMEMCTRL_KSVCTRLUPD_MASK, 0); return valid; } -static void _dw_hdcp1x_set_rxdetect(u8 bit) -{ - hdmi_trace("dw hdcp set rx detect: %s\n", bit ? "enable" : "disable"); - dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_RXDETECT_MASK, bit); -} - -static void _dw_hdcp1x_set_encrypt(u8 bit) -{ - hdmi_trace("dw hdcp set encrypt: %s\n", bit ? "enable" : "disable"); - dw_write_mask(A_HDCPCFG1, A_HDCPCFG1_ENCRYPTIONDISABLE_MASK, !bit); -} - -static void _dw_hdcp1x_interrupt_clear(u8 value) -{ - dw_write(A_APIINTCLR, value); -} - -static void _dw_hdcp1x_set_oess_size(u8 value) -{ - hdmi_trace("dw hdcp set oess size: %d\n", value); - dw_write(A_OESSWCFG, value); -} - u8 _dw_hdcp1x_status_handler(int *param, u32 irq_stat) { - int valid = HDCP_IDLE; + int valid = DW_HDCP1X_IDLE; if (irq_stat != 0) hdcp_log("hdcp get interrupt state: 0x%x\n", irq_stat); if (irq_stat == 0) { - if (hdcp->hdcp1x_encry_delay && (hdcp->hdcp1x_auth_state == HDCP_ENGAGED)) { + if (hdcp->hdcp1x_encry_delay && (hdcp->hdcp1x_auth_state == DW_HDCP1X_ENGAGED)) { hdcp->hdcp1x_encry_delay++; if (hdcp->hdcp1x_encry_delay >= 20) { - _dw_hdcp1x_set_encrypt(true); + _dw_hdcp1x_set_encrypt(DW_HDMI_ENABLE); hdcp->hdcp1x_encry_delay = 0; - hdcp->hdcp1x_encrying = 0x1; - hdmi_inf("hdcp start encryption\n"); + hdcp->hdcp1x_encrying = DW_HDMI_ENABLE; + hdmi_inf("dw hdcp1x start encryption\n"); } } @@ -444,21 +429,21 @@ u8 _dw_hdcp1x_status_handler(int *param, u32 irq_stat) } if ((irq_stat & A_APIINTSTAT_KEEPOUTERRORINT_MASK) != 0) { - hdcp->hdcp1x_auth_state = HDCP_FAILED; + hdcp->hdcp1x_auth_state = DW_HDCP1X_FAILED; hdcp->hdcp1x_encry_delay = 0; - return HDCP_FAILED; + return DW_HDCP1X_FAILED; } if ((irq_stat & A_APIINTSTAT_LOSTARBITRATION_MASK) != 0) { - hdcp->hdcp1x_auth_state = HDCP_FAILED; + hdcp->hdcp1x_auth_state = DW_HDCP1X_FAILED; hdcp->hdcp1x_encry_delay = 0; - return HDCP_FAILED; + return DW_HDCP1X_FAILED; } if ((irq_stat & A_APIINTSTAT_I2CNACK_MASK) != 0) { - hdcp->hdcp1x_auth_state = HDCP_FAILED; + hdcp->hdcp1x_auth_state = DW_HDCP1X_FAILED; hdcp->hdcp1x_encry_delay = 0; - return HDCP_FAILED; + return DW_HDCP1X_FAILED; } if (irq_stat & A_APIINTSTAT_KSVSHA1CALCINT_MASK) @@ -467,16 +452,16 @@ u8 _dw_hdcp1x_status_handler(int *param, u32 irq_stat) if ((irq_stat & A_APIINTSTAT_HDCP_FAILED_MASK) != 0) { *param = 0; _dw_hdcp1x_set_encrypt(false); - hdcp->hdcp1x_auth_state = HDCP_FAILED; + hdcp->hdcp1x_auth_state = DW_HDCP1X_FAILED; hdcp->hdcp1x_encry_delay = 0; - return HDCP_FAILED; + return DW_HDCP1X_FAILED; } if ((irq_stat & A_APIINTSTAT_HDCP_ENGAGED_MASK) != 0) { *param = 1; - hdcp->hdcp1x_auth_state = HDCP_ENGAGED; + hdcp->hdcp1x_auth_state = DW_HDCP1X_ENGAGED; hdcp->hdcp1x_encry_delay = 1; - return HDCP_ENGAGED; + return DW_HDCP1X_ENGAGED; } return valid; @@ -494,71 +479,50 @@ static int _dw_hdcp1x_get_encrypt_state(void) } hdcp14_status = dw_read(A_APIINTSTAT); - _dw_hdcp1x_interrupt_clear(hdcp14_status); + _dw_hdcp1x_int_clear(hdcp14_status); ret = _dw_hdcp1x_status_handler(¶m, (u32)hdcp14_status); - if ((ret != HDCP_ERR_KSV_LIST_NOT_VALID) && (ret != HDCP_FAILED)) + if ((ret != DW_HDCP1X_KSV_ERR_INVALID) && (ret != DW_HDCP1X_FAILED)) return DW_HDCP_SUCCESS; return DW_HDCP_FAILED; } -static int _dw_hdcp1x_start_auth(void) +int dw_hdcp1x_enable(void) { - u8 hdcp_mask = 0, data = 0; + u8 hdcp_mask = 0; if (hdcp->hdcp1x_auth_done) { - hdmi_inf("hdcp14 has been auth done!\n"); - return -1; + hdmi_inf("dw hdcp1x has been auth done!\n"); + return 0; } - /* disable encrypt */ - _dw_hdcp1x_set_encrypt(false); - - /* enable hdcp keepout */ - dw_fc_video_set_hdcp_keepout(true); + /* 1. disable hdcp config for hdcp1x enable flow */ + _dw_hdcp1x_set_encrypt(DW_HDMI_DISABLE); + _dw_hdcp1x_set_rxdetect(DW_HDMI_DISABLE); + _dw_hdcp1x_set_data_polarity(DW_HDMI_DISABLE); - /* config hdcp work mode */ + /* 2. set hdcp1x data path for hdcp1x enable flow */ dw_hdcp_sync_tmds_mode(); - - /* config Hsync and Vsync polarity and enable */ dw_hdcp_sync_data_polarity(); - - /* bypass hdcp_block = 0 */ - dw_write_mask(0x4003, 1 << 5, 0x0); - - /* config use hdcp14 path */ - dw_hdcp_set_data_path(0x0); - - /* config hdcp14 feature11 */ - dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_EN11FEATURE_MASK, 0x0); - - /* config hdcp14 ri check mode */ - dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_SYNCRICHECK_MASK, 0x0); - - /* config hdcp14 i2c mode */ - dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_I2CFASTMODE_MASK, 0x0); - - dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_ELVENA_MASK, 0x0); - - /* fixed */ - dw_hdcp_set_avmute_state(false); - - /* config send color when sending unencrtypted video data */ + dw_fc_video_set_hdcp_keepout(DW_HDMI_ENABLE); + dw_hdcp2x_ovr_set_path(DW_HDMI_DISABLE, DW_HDMI_ENABLE); + + /* 3. set hdcp1x basic config for hdcp1x enable flow */ + dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_EN11FEATURE_MASK, DW_HDMI_DISABLE); + dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_SYNCRICHECK_MASK, DW_HDMI_DISABLE); + dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_I2CFASTMODE_MASK, DW_HDMI_DISABLE); + dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_ELVENA_MASK, DW_HDMI_DISABLE); dw_write_mask(A_VIDPOLCFG, A_VIDPOLCFG_UNENCRYPTCONF_MASK, 0x2); + dw_write_mask(A_HDCPCFG1, A_HDCPCFG1_PH2UPSHFTENC_MASK, DW_HDMI_ENABLE); - /* set enable encoding packet header */ - dw_write_mask(A_HDCPCFG1, A_HDCPCFG1_PH2UPSHFTENC_MASK, 0x1); - - /* config encryption oess size */ _dw_hdcp1x_set_oess_size(DW_HDCP14_OESS_SIZE); + dw_hdcp1x_set_avmute(DW_HDMI_DISABLE); - /* software reset hdcp14 engine */ - dw_write_mask(A_HDCPCFG1, A_HDCPCFG1_SWRESET_MASK, 0x0); - - /* enable hdcp14 rx detect for start auth */ - _dw_hdcp1x_set_rxdetect(true); + /* 4. set hdcp1x hardware reset for hdcp1x enable flow */ + dw_write_mask(A_HDCPCFG1, A_HDCPCFG1_SWRESET_MASK, DW_HDMI_DISABLE); + /* 5. mask and clear hdcp1x interrupt state */ hdcp_mask = A_APIINTCLR_KSVACCESSINT_MASK; hdcp_mask |= A_APIINTCLR_KSVSHA1CALCINT_MASK; hdcp_mask |= A_APIINTCLR_KEEPOUTERRORINT_MASK; @@ -566,49 +530,28 @@ static int _dw_hdcp1x_start_auth(void) hdcp_mask |= A_APIINTCLR_I2CNACK_MASK; hdcp_mask |= A_APIINTCLR_HDCP_FAILED_MASK; hdcp_mask |= A_APIINTCLR_HDCP_ENGAGED_MASK; - _dw_hdcp1x_interrupt_clear(hdcp_mask); - - hdcp_mask = A_APIINTMSK_KSVACCESSINT_MASK; - hdcp_mask |= A_APIINTMSK_KSVSHA1CALCINT_MASK; - hdcp_mask |= A_APIINTMSK_KEEPOUTERRORINT_MASK; - hdcp_mask |= A_APIINTMSK_LOSTARBITRATION_MASK; - hdcp_mask |= A_APIINTMSK_I2CNACK_MASK; - hdcp_mask |= A_APIINTMSK_SPARE_MASK; - hdcp_mask |= A_APIINTMSK_HDCP_FAILED_MASK; - hdcp_mask |= A_APIINTMSK_HDCP_ENGAGED_MASK; - data = (~hdcp_mask) & dw_read(A_APIINTMSK); - dw_write(A_APIINTMSK, data); - - hdcp->hdcp1x_auth_done = 0x1; + _dw_hdcp1x_int_clear(hdcp_mask); + _dw_hdcp1x_int_mask(hdcp_mask); - return 0; -} - -int dw_hdcp1x_enable(void) -{ - int ret = 0; - - hdcp->hdcp1x_auth_state = HDCP_FAILED; - ret = _dw_hdcp1x_start_auth(); - if (ret != 0) { - hdmi_err("dw hdcp14 start auth failed\n"); - return -1; - } + /* 6. enable and start auth for hdcp1x enable flow */ + _dw_hdcp1x_set_rxdetect(DW_HDMI_ENABLE); + dw_mc_set_hdcp_clk(DW_HDMI_ENABLE); + hdcp->hdcp1x_auth_done = DW_HDMI_ENABLE; + hdcp->hdcp1x_auth_state = DW_HDCP1X_FAILED; dw_hdcp_set_enable_type(DW_HDCP_TYPE_HDCP14); return 0; } int dw_hdcp1x_disable(void) { - /* 1. disable encryption */ - _dw_hdcp1x_set_encrypt(false); + _dw_hdcp1x_set_encrypt(DW_HDMI_DISABLE); dw_hdcp_set_enable_type(DW_HDCP_TYPE_NULL); - hdcp->hdcp1x_auth_state = HDCP_FAILED; - hdcp->hdcp1x_auth_done = 0x0; - hdcp->hdcp1x_encrying = 0x0; + hdcp->hdcp1x_auth_state = DW_HDCP1X_FAILED; + hdcp->hdcp1x_auth_done = DW_HDMI_DISABLE; + hdcp->hdcp1x_encrying = DW_HDMI_DISABLE; hdcp_log("hdcp14 disconfig done!\n"); return 0; } @@ -625,27 +568,6 @@ int dw_hdcp_get_state(void) return ret; } -void dw_hdcp_config_init(void) -{ - /* init hdcp14 oess windows size is DW_HDCP14_OESS_SIZE */ - _dw_hdcp1x_set_oess_size(DW_HDCP14_OESS_SIZE); - - /* frame composer keepout hdcp */ - dw_fc_video_set_hdcp_keepout(true); - - /* main control enable hdcp clock */ - dw_mc_disable_hdcp_clock(false); - - /* disable hdcp14 rx detect */ - _dw_hdcp1x_set_rxdetect(false); - - /* disable hdcp14 encrypt */ - _dw_hdcp1x_set_encrypt(false); - - /* disable hdcp data polarity */ - dw_write_mask(A_VIDPOLCFG, A_VIDPOLCFG_DATAENPOL_MASK, 0x0); -} - void dw_hdcp_initial(void) { struct dw_hdmi_dev_s *hdmi = dw_get_hdmi(); @@ -655,14 +577,14 @@ void dw_hdcp_initial(void) dw_i2cm_re_init(); /* enable hdcp14 bypass encryption */ - dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_BYPENCRYPTION_MASK, 0x0); + dw_write_mask(A_HDCPCFG0, A_HDCPCFG0_BYPENCRYPTION_MASK, DW_HDMI_DISABLE); /* disable hdcp14 encryption */ - _dw_hdcp1x_set_encrypt(false); + _dw_hdcp1x_set_encrypt(DW_HDMI_DISABLE); /* reset hdcp14 status flag */ - hdcp->hdcp1x_auth_done = 0x0; - hdcp->hdcp1x_encrying = 0x0; + hdcp->hdcp1x_auth_done = DW_HDMI_DISABLE; + hdcp->hdcp1x_encrying = DW_HDMI_DISABLE; } void dw_hdcp_exit(void) @@ -674,23 +596,23 @@ ssize_t dw_hdcp_dump(char *buf) { ssize_t n = 0; - if (_dw_hdcp_get_enable_type() == 0x0) - return n; - n += sprintf(buf + n, "[dw hdcp]:\n"); n += sprintf(buf + n, " - tmds mode : [%s]\n", dw_read_mask(A_HDCPCFG0, A_HDCPCFG0_HDMIDVI_MASK) ? "hdmi" : "dvi"); n += sprintf(buf + n, " - data path : [%s]\n", - _dw_hdcp_get_data_path() ? "hdcp2x" : "hdcp1x"); + dw_hdcp2x_get_path() ? "hdcp2x" : "hdcp1x"); n += sprintf(buf + n, " - hdcp clock : [%s]\n", dw_mc_get_hdcp_clk() ? "disable" : "enable"); + if (_dw_hdcp_get_enable_type() == 0x0) + return n; + if (_dw_hdcp_get_enable_type() & BIT(DW_HDCP_TYPE_HDCP14)) { n += sprintf(buf + n, " - [dw hdcp1x]\n"); n += sprintf(buf + n, "\t- auth config: %s\n", hdcp->hdcp1x_auth_done ? "done" : "not-done"); n += sprintf(buf + n, "\t- auth state : %s\n", - hdcp->hdcp1x_auth_state == HDCP_ENGAGED ? "success" : "failed"); + hdcp->hdcp1x_auth_state == DW_HDCP1X_ENGAGED ? "success" : "failed"); n += sprintf(buf + n, "\t- hw encrying: %s\n", hdcp->hdcp1x_encrying ? "enable" : "disable"); n += sprintf(buf + n, "\t- sw encrying: %s\n", diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp.h b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp.h index b3a767bb22..4068bc25e4 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp.h +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp.h @@ -30,7 +30,7 @@ int dw_hdcp_set_enable_type(int type); * @enable: 1 - enable hdcp avmute * 0 - disable hdcp avmute */ -void dw_hdcp_set_avmute_state(int enable); +void dw_hdcp1x_set_avmute(int enable); /** * @desc: dw hdcp sync config tmds mode from framecomposer */ @@ -39,21 +39,11 @@ void dw_hdcp_sync_tmds_mode(void); * @desc: dw hdcp sync config data polarity from framecomposer */ void dw_hdcp_sync_data_polarity(void); -/** - * @desc: dw hdcp config data pth - * @path: 0 - hdcp14 path - * 1 - hdcp22 path - */ -void dw_hdcp_set_data_path(u8 path); /** * @desc: check hdcp encrypt status and handle the status * @return: refer to enum dw_hdcp_state_e */ int dw_hdcp_get_state(void); -/** - * @desc: dw hdcp api for config init - */ -void dw_hdcp_config_init(void); /** * @desc: dw hdcp api for init */ diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp22.c b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp22.c index 4b15a6f752..fc9951aa47 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp22.c +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp22.c @@ -32,17 +32,22 @@ static struct dw_hdcp_s *hdcp; static esm_instance_t *esm; +static inline void _dw_hdcp2x_int_mute(u8 value) +{ + dw_write(HDCP22REG_MUTE, value); +} + /** * @desc: chose which way to enable hdcp22 * @enable: 0 - chose to enable hdcp22 by dwc_hdmi inner signal ist_hdcp_capable * 1 - chose to enable hdcp22 by hdcp22_ovr_val bit */ -static void _dw_hdcp2x_set_avmute(u8 val, u8 enable) +static void _dw_hdcp2x_ovr_set_avmute(u8 ovr_val, u8 ovr_en) { dw_write_mask(HDCP22REG_CTRL1, - HDCP22REG_CTRL1_HDCP22_AVMUTE_OVR_VAL_MASK, val); + HDCP22REG_CTRL1_HDCP22_AVMUTE_OVR_VAL_MASK, ovr_val); dw_write_mask(HDCP22REG_CTRL1, - HDCP22REG_CTRL1_HDCP22_AVMUTE_OVR_EN_MASK, enable); + HDCP22REG_CTRL1_HDCP22_AVMUTE_OVR_EN_MASK, ovr_en); } /** @@ -51,22 +56,40 @@ static void _dw_hdcp2x_set_avmute(u8 val, u8 enable) * 1 - hdcp22 hpd come from hpd_ovr_val * @enable:hpd_ovr_val */ -static void _dw_hdcp2x_set_hpd(u8 val) +static void _dw_hdcp2x_ovr_set_hpd(u8 ovr_val, u8 ovr_en) { - dw_write_mask(HDCP22REG_CTRL, - HDCP22REG_CTRL_HPD_OVR_VAL_MASK, val); - dw_write_mask(HDCP22REG_CTRL, - HDCP22REG_CTRL_HPD_OVR_EN_MASK, 0x1); + dw_write_mask(HDCP22REG_CTRL, HDCP22REG_CTRL_HPD_OVR_VAL_MASK, ovr_val); + dw_write_mask(HDCP22REG_CTRL, HDCP22REG_CTRL_HPD_OVR_EN_MASK, ovr_en); } void _dw_hdcp2x_data_enable(u8 enable) { - dw_mc_disable_hdcp_clock(enable ? 0x0 : 0x1); - _dw_hdcp2x_set_avmute(enable ? 0x0 : 0x1, 0x1); + if (enable == DW_HDMI_ENABLE) { + _dw_hdcp2x_ovr_set_avmute(DW_HDMI_DISABLE, DW_HDMI_ENABLE); + dw_mc_set_hdcp_clk(DW_HDMI_ENABLE); + return; + } + + dw_mc_set_hdcp_clk(DW_HDMI_DISABLE); + _dw_hdcp2x_ovr_set_avmute(DW_HDMI_DISABLE, DW_HDMI_ENABLE); +} + +/** + * @path: 0 - hdcp14 path + * 1 - hdcp22 path + */ +void dw_hdcp2x_ovr_set_path(u8 ovr_val, u8 ovr_en) +{ + dw_write_mask(HDCP22REG_CTRL, HDCP22REG_CTRL_HDCP22_OVR_VAL_MASK, ovr_val); + dw_write_mask(HDCP22REG_CTRL, HDCP22REG_CTRL_HDCP22_OVR_EN_MASK, ovr_en); } -static int -_esm_hpi_read(void *instance, uint32_t offset, uint32_t *data) +u8 dw_hdcp2x_get_path(void) +{ + return dw_read_mask(HDCP22REG_STS, HDCP22REG_STS_HDCP22_SWITCH); +} + +static int _esm_hpi_read(void *instance, uint32_t offset, uint32_t *data) { unsigned long addr = esm->driver->hpi_base + offset; @@ -75,8 +98,7 @@ _esm_hpi_read(void *instance, uint32_t offset, uint32_t *data) return 0; } -static int -_esm_hpi_write(void *instance, uint32_t offset, uint32_t data) +static int _esm_hpi_write(void *instance, uint32_t offset, uint32_t data) { unsigned long addr = esm->driver->hpi_base + offset; *((volatile u32 *)addr) = data; @@ -84,22 +106,22 @@ _esm_hpi_write(void *instance, uint32_t offset, uint32_t data) return 0; } -static int -_esm_data_read(void *instance, uint32_t offset, uint8_t *dest_buf, uint32_t nbytes) +static int _esm_data_read(void *instance, uint32_t offset, + uint8_t *dest_buf, uint32_t nbytes) { memcpy(dest_buf, (u8 *)(esm->driver->vir_data_base + offset), nbytes); return 0; } -static int -_esm_data_write(void *instance, uint32_t offset, uint8_t *src_buf, uint32_t nbytes) +static int _esm_data_write(void *instance, uint32_t offset, + uint8_t *src_buf, uint32_t nbytes) { memcpy((u8 *)(esm->driver->vir_data_base + offset), src_buf, nbytes); return 0; } -static int -_esm_data_set(void *instance, uint32_t offset, uint8_t data, uint32_t nbytes) +static int _esm_data_set(void *instance, uint32_t offset, + uint8_t data, uint32_t nbytes) { memset((u8 *)(esm->driver->vir_data_base + offset), data, nbytes); return 0; @@ -143,7 +165,7 @@ static void _dw_hdcp2x_auth_work(struct work_struct *work) return; } - hdcp->esm_auth_done = 0x1; + hdcp->esm_auth_done = DW_HDMI_ENABLE; } /** @@ -158,57 +180,57 @@ static int _dw_hdcp2x_get_encry_state(void) uint32_t state = 0; ESM_STATUS ret = ESM_HL_SUCCESS; - if (ESM_GetState(esm, &state, &Status) == ESM_HL_SUCCESS) { - - if (Status.esm_sync_lost) { - hdmi_err("[hdcp2.2-error]esm sync lost!\n"); - return -1; - } + ret = ESM_GetState(esm, &state, &Status); + if (ret != ESM_HL_SUCCESS) + return -1; - if (Status.esm_exception) { - /* Got an exception. can check */ - /* bits for more detail */ - if (Status.esm_exception & 0x80000000) - hdmi_inf("hardware exception\n"); - else - hdmi_inf("solfware exception\n"); - - hdmi_inf("exception line number:%d\n", - (Status.esm_exception >> 10) & 0xfffff); - hdmi_inf("exception flag:%d\n", - (Status.esm_exception >> 1) & 0x1ff); - hdmi_inf("exception Type:%s\n", - (Status.esm_exception & 0x1) ? "notify" : "abort"); - if (((Status.esm_exception >> 1) & 0x1ff) != 109) - return -1; - - if (hdcp->esm_pairdata) { - memset(hdcp->esm_pairdata, 0, DW_ESM_PAIRDATA_SIZE); - ret = ESM_SavePairing(esm, hdcp->esm_pairdata, - &esm->esm_pair_size); - if (ret != ESM_HL_SUCCESS) - hdmi_err("ESM_SavePairing failed\n"); - } - - return 1; - } + if (Status.esm_sync_lost) { + hdmi_err("[hdcp2.2-error]esm sync lost!\n"); + return -1; + } - if (Status.esm_auth_fail) { - hdmi_err("esm status check result,failed:%d\n", Status.esm_auth_fail); + if (Status.esm_exception) { + /* Got an exception. can check */ + /* bits for more detail */ + if (Status.esm_exception & 0x80000000) + hdmi_inf("hardware exception\n"); + else + hdmi_inf("solfware exception\n"); + + hdmi_inf(" - line number:%d\n", + (Status.esm_exception >> 10) & 0xfffff); + hdmi_inf(" - flag:%d\n", + (Status.esm_exception >> 1) & 0x1ff); + hdmi_inf(" - Type:%s\n", + (Status.esm_exception & 0x1) ? "notify" : "abort"); + if (((Status.esm_exception >> 1) & 0x1ff) != 109) return -1; - } - if (Status.esm_auth_pass) { + if (hdcp->esm_pairdata) { memset(hdcp->esm_pairdata, 0, DW_ESM_PAIRDATA_SIZE); - ret = ESM_SavePairing(esm, hdcp->esm_pairdata, &esm->esm_pair_size); + ret = ESM_SavePairing(esm, hdcp->esm_pairdata, + &esm->esm_pair_size); if (ret != ESM_HL_SUCCESS) hdmi_err("ESM_SavePairing failed\n"); - return 0; } - return 2; + return 1; + } + + if (Status.esm_auth_fail) { + hdmi_err("esm status check result,failed:%d\n", Status.esm_auth_fail); + return -1; } - return -1; + + if (Status.esm_auth_pass) { + memset(hdcp->esm_pairdata, 0, DW_ESM_PAIRDATA_SIZE); + ret = ESM_SavePairing(esm, hdcp->esm_pairdata, &esm->esm_pair_size); + if (ret != ESM_HL_SUCCESS) + hdmi_err("ESM_SavePairing failed\n"); + return 0; + } + + return 2; } static int _dw_hdcp2x_open(void) @@ -248,7 +270,7 @@ static int _dw_hdcp2x_open(void) if (ESM_LoadPairing(esm, hdcp->esm_pairdata, esm->esm_pair_size) < 0) hdmi_inf("ESM Load Pairing failed\n"); - hdcp->esm_open = 0x1; + hdcp->esm_open = DW_HDMI_ENABLE; set_capability: if (hdcp->esm_cap_done) @@ -258,11 +280,13 @@ static int _dw_hdcp2x_open(void) /* Enable logging */ ESM_LogControl(esm, 1, 0); /* ESM_EnableLowValueContent(esm); */ - if (ESM_SetCapability(esm) != ESM_HL_SUCCESS) { - hdmi_err("esm set capability fail, maybe remote Rx is not 2.2 capable!\n"); + err = ESM_SetCapability(esm); + if (err != ESM_HL_SUCCESS) { + hdmi_err("dw hdcp2x esm set capability failed!\n"); return -1; } - hdcp->esm_cap_done = 0x1; + hdcp->esm_cap_done = DW_HDMI_ENABLE; + msleep(50); queue_work(hdcp->hdcp2x_workqueue, &hdcp->hdcp2x_work); return 0; @@ -279,12 +303,12 @@ int dw_hdcp2x_get_encrypt_state(void) ret = _dw_hdcp2x_get_encry_state(); if (ret == 0) { - _dw_hdcp2x_data_enable(1); + _dw_hdcp2x_data_enable(DW_HDMI_ENABLE); hdcp->esm_auth_state = DW_HDCP_SUCCESS; hdmi_inf("dw hdcp2x enable data encry\n"); goto esm_exit; } else if (ret == -1) { - _dw_hdcp2x_data_enable(0); + _dw_hdcp2x_data_enable(DW_HDMI_DISABLE); msleep(25); if (!_dw_hdcp2x_start_auth()) { hdcp->esm_auth_state = DW_HDCP_ING; @@ -309,11 +333,13 @@ int dw_hdcp2x_get_encrypt_state(void) /* configure hdcp2.2 and enable hdcp2.2 encrypt */ int dw_hdcp2x_enable(void) { + u8 hdcp_mask = 0; + /* 1 - set main controller hdcp clock disable */ - _dw_hdcp2x_data_enable(0); + _dw_hdcp2x_data_enable(DW_HDMI_DISABLE); /* 2 - set hdcp keepout */ - dw_fc_video_set_hdcp_keepout(true); + dw_fc_video_set_hdcp_keepout(DW_HDMI_ENABLE); /* 3 - Select DVI or HDMI mode */ dw_hdcp_sync_tmds_mode(); @@ -321,19 +347,21 @@ int dw_hdcp2x_enable(void) /* 4 - Set the Data enable, Hsync, and VSync polarity */ dw_hdcp_sync_data_polarity(); - dw_write_mask(0x4003, 1 << 5, 0x1); - - dw_hdcp_set_data_path(0x1); + dw_hdcp2x_ovr_set_path(DW_HDMI_ENABLE, DW_HDMI_ENABLE); - _dw_hdcp2x_set_hpd(0x1); + _dw_hdcp2x_ovr_set_hpd(DW_HDMI_ENABLE, DW_HDMI_ENABLE); /* disable avmute overwrite */ - _dw_hdcp2x_set_avmute(0x0, 0x0); - - dw_write_mask(0x4003, 1 << 4, 0x1); + _dw_hdcp2x_ovr_set_avmute(DW_HDMI_DISABLE, DW_HDMI_DISABLE); /* mask the interrupt of hdcp22 event */ - dw_write_mask(HDCP22REG_MASK, 0xff, 0); + hdcp_mask = HDCP22REG_MUTE_CAPABLE_MASK; + hdcp_mask |= HDCP22REG_MUTE_NOT_CAPABLE_MASK; + hdcp_mask |= HDCP22REG_MUTE_AUTHEN_LOST_MASK; + hdcp_mask |= HDCP22REG_MUTE_AUTHEN_MASK; + hdcp_mask |= HDCP22REG_MUTE_AUTHEN_FAIL_MASK; + hdcp_mask |= HDCP22REG_MUTE_DECRYP_CHG_MASK; + _dw_hdcp2x_int_mute(hdcp_mask); if (_dw_hdcp2x_open() < 0) return -1; @@ -345,15 +373,11 @@ int dw_hdcp2x_enable(void) int dw_hdcp2x_disable(void) { - dw_mc_disable_hdcp_clock(1); - - dw_write_mask(0x4003, 1 << 5, 0x0); - - dw_hdcp_set_data_path(0x0); + dw_mc_set_hdcp_clk(DW_HDMI_DISABLE); - _dw_hdcp2x_set_hpd(0x0); + dw_hdcp2x_ovr_set_path(DW_HDMI_DISABLE, DW_HDMI_ENABLE); - dw_write_mask(0x4003, 1 << 4, 0x0); + _dw_hdcp2x_ovr_set_hpd(DW_HDMI_DISABLE, DW_HDMI_ENABLE); if (hdcp->esm_auth_done) { mutex_lock(&hdcp->lock_esm_auth); @@ -362,8 +386,8 @@ int dw_hdcp2x_disable(void) msleep(20); } - hdcp->esm_auth_done = 0x0; - hdcp->esm_cap_done = 0x0; + hdcp->esm_auth_done = DW_HDMI_DISABLE; + hdcp->esm_cap_done = DW_HDMI_DISABLE; hdcp->esm_auth_state = DW_HDCP_DISABLE; dw_hdcp_set_enable_type(DW_HDCP_TYPE_NULL); @@ -391,8 +415,8 @@ int dw_hdcp2x_firmware_update(const u8 *data, size_t size) } memcpy(esm_addr, data, size); - hdcp->esm_size = (u32)size; - hdcp->esm_loading = 0x1; + hdcp->esm_size = (u32)size; + hdcp->esm_loading = DW_HDMI_ENABLE; hdmi_inf("dw hdcp2x loading firmware size %d finish.\n", (u32)size); return 0; @@ -404,35 +428,26 @@ int dw_hdcp2x_init(void) hdcp = &hdmi->hdcp_dev; - hdcp->esm_loading = 0x0; - hdcp->esm_open = 0x0; - hdcp->esm_auth_done = 0x0; - hdcp->esm_cap_done = 0x0; + hdcp->esm_open = DW_HDMI_DISABLE; + hdcp->esm_loading = DW_HDMI_DISABLE; + hdcp->esm_auth_done = DW_HDMI_DISABLE; + hdcp->esm_cap_done = DW_HDMI_DISABLE; - if (hdcp->esm_pairdata != NULL) { - kfree(hdcp->esm_pairdata); - hdcp->esm_pairdata = NULL; - } + shdmi_free_point(hdcp->esm_pairdata); hdcp->esm_pairdata = kzalloc(DW_ESM_PAIRDATA_SIZE, GFP_KERNEL | __GFP_ZERO); if (IS_ERR_OR_NULL(hdcp->esm_pairdata)) { shdmi_err(hdcp->esm_pairdata); return -1; } - if (esm != NULL) { - kfree(esm); - esm = NULL; - } + shdmi_free_point(esm); esm = kzalloc(sizeof(esm_instance_t), GFP_KERNEL | __GFP_ZERO); if (IS_ERR_OR_NULL(esm)) { shdmi_err(esm); return -1; } - if (esm->driver != NULL) { - kfree(esm->driver); - esm->driver = NULL; - } + shdmi_free_point(esm->driver); esm->driver = kzalloc(sizeof(esm_host_driver_t), GFP_KERNEL | __GFP_ZERO); if (IS_ERR_OR_NULL(esm->driver)) { shdmi_err(esm->driver); @@ -484,25 +499,13 @@ int dw_hdcp2x_init(void) void dw_hdcp2x_exit(void) { - if (hdcp->hdcp2x_workqueue != NULL) { - kfree(hdcp->hdcp2x_workqueue); - hdcp->hdcp2x_workqueue = NULL; - } + shdmi_free_point(esm->driver); - if (esm->driver != NULL) { - kfree(esm->driver); - esm->driver = NULL; - } + shdmi_free_point(esm); - if (esm != NULL) { - kfree(esm); - esm = NULL; - } + shdmi_free_point(hdcp->hdcp2x_workqueue); - if (hdcp != NULL) { - kfree(hdcp); - hdcp = NULL; - } + shdmi_free_point(hdcp); } ssize_t dw_hdcp2x_dump(char *buf) diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp22.h b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp22.h index fa73fe9103..3ac9d5c74a 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp22.h +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_hdcp22.h @@ -18,6 +18,18 @@ * DW HDCP2.x Function * * * *****************************************************************************/ +/** + * @desc: dw hdcp config data pth + * @path: 0 - hdcp14 path + * 1 - hdcp22 path + */ +void dw_hdcp2x_ovr_set_path(u8 ovr_val, u8 ovr_en); +/** + * @desc: dw hdcp get data path + * @return: 0 - hdcp1x path + * 1 - hdcp2x path + */ +u8 dw_hdcp2x_get_path(void); /** * @desc: dw hdcp2x get encry state * @return: refer to enum dw_hdcp_state_e diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_mc.c b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_mc.c index 3c06974d32..ecad1d25e8 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_mc.c +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_mc.c @@ -31,29 +31,29 @@ static irq_vector_t irq_vec[] = { {0, 0, 0}, }; -void _dw_mc_disable_csc_clock(u8 bit) +void _dw_mc_set_csc_clk(u8 bit) { - dw_write_mask(MC_CLKDIS, MC_CLKDIS_CSCCLK_DISABLE_MASK, bit); + dw_write_mask(MC_CLKDIS, MC_CLKDIS_CSCCLK_DISABLE_MASK, !bit); } -void _dw_mc_disable_tmds_clock(u8 bit) +void _dw_mc_set_tmds_clk(u8 bit) { - dw_write_mask(MC_CLKDIS, MC_CLKDIS_TMDSCLK_DISABLE_MASK, bit); + dw_write_mask(MC_CLKDIS, MC_CLKDIS_TMDSCLK_DISABLE_MASK, !bit); } -void _dw_mc_disable_pixel_clock(u8 bit) +void _dw_mc_set_pixel_clk(u8 bit) { - dw_write_mask(MC_CLKDIS, MC_CLKDIS_PIXELCLK_DISABLE_MASK, bit); + dw_write_mask(MC_CLKDIS, MC_CLKDIS_PIXELCLK_DISABLE_MASK, !bit); } -void _dw_mc_disable_pixel_repetition_clock(u8 bit) +void _dw_mc_set_pixel_rep_clk(u8 bit) { - dw_write_mask(MC_CLKDIS, MC_CLKDIS_PREPCLK_DISABLE_MASK, bit); + dw_write_mask(MC_CLKDIS, MC_CLKDIS_PREPCLK_DISABLE_MASK, !bit); } -void dw_mc_disable_hdcp_clock(u8 bit) +void dw_mc_set_hdcp_clk(u8 bit) { - dw_write_mask(MC_CLKDIS, MC_CLKDIS_HDCPCLK_DISABLE_MASK, bit); + dw_write_mask(MC_CLKDIS, MC_CLKDIS_HDCPCLK_DISABLE_MASK, !bit); } u8 dw_mc_get_hdcp_clk(void) @@ -61,24 +61,24 @@ u8 dw_mc_get_hdcp_clk(void) return dw_read_mask(MC_CLKDIS, MC_CLKDIS_HDCPCLK_DISABLE_MASK); } -void dw_mc_disable_cec_clock(u8 bit) +void dw_mc_set_cec_clk(u8 bit) { - dw_write_mask(MC_CLKDIS, MC_CLKDIS_CECCLK_DISABLE_MASK, bit); + dw_write_mask(MC_CLKDIS, MC_CLKDIS_CECCLK_DISABLE_MASK, !bit); } -void dw_mc_disable_audio_sampler_clock(u8 bit) +void dw_mc_set_audio_sample_clk(u8 bit) { - dw_write_mask(MC_CLKDIS, MC_CLKDIS_AUDCLK_DISABLE_MASK, bit); + dw_write_mask(MC_CLKDIS, MC_CLKDIS_AUDCLK_DISABLE_MASK, !bit); } -u8 dw_mc_get_audio_sample_clock(void) +u8 dw_mc_get_audio_sample_clk(void) { return (u8)dw_read_mask(MC_CLKDIS, MC_CLKDIS_AUDCLK_DISABLE_MASK); } -void _dw_mc_video_feed_through_off(u8 bit) +void _dw_mc_set_csc_bypass(u8 bit) { - dw_write_mask(MC_FLOWCTRL, MC_FLOWCTRL_FEED_THROUGH_OFF_MASK, bit); + dw_write_mask(MC_FLOWCTRL, MC_FLOWCTRL_FEED_THROUGH_OFF_MASK, !bit); } void dw_mc_reset_audio_i2s(void) @@ -103,27 +103,31 @@ void dw_mc_all_clock_enable(void) hdmi_trace("dw hdmi mc enable all clock\n"); - _dw_mc_video_feed_through_off(0); - _dw_mc_disable_pixel_clock(0); - _dw_mc_disable_tmds_clock(0); - val = (hdmi->pixel_repeat > 0) ? 0 : 1; - _dw_mc_disable_pixel_repetition_clock(val); - _dw_mc_disable_csc_clock(0); - val = (hdmi->audio_on) ? 0 : 1; - dw_mc_disable_audio_sampler_clock(val); - dw_mc_disable_hdcp_clock(1);/* disable it */ + _dw_mc_set_csc_bypass(DW_HDMI_ENABLE); + _dw_mc_set_pixel_clk(DW_HDMI_ENABLE); + _dw_mc_set_tmds_clk(DW_HDMI_ENABLE); + + val = (hdmi->pixel_repeat > 0) ? DW_HDMI_ENABLE : DW_HDMI_DISABLE; + _dw_mc_set_pixel_rep_clk(val); + _dw_mc_set_csc_clk(DW_HDMI_ENABLE); + + val = (hdmi->audio_on) ? DW_HDMI_ENABLE : DW_HDMI_DISABLE; + dw_mc_set_audio_sample_clk(val); + dw_mc_set_hdcp_clk(DW_HDMI_DISABLE);/* disable it */ } void dw_mc_all_clock_disable(void) { hdmi_trace("dw hdmi mc disable all clock\n"); - _dw_mc_disable_pixel_clock(1); - _dw_mc_disable_tmds_clock(1); - _dw_mc_disable_pixel_repetition_clock(1); - _dw_mc_disable_csc_clock(1); - dw_mc_disable_audio_sampler_clock(1); - dw_mc_disable_cec_clock(1); - dw_mc_disable_hdcp_clock(1); + + _dw_mc_set_pixel_clk(DW_HDMI_DISABLE); + _dw_mc_set_tmds_clk(DW_HDMI_DISABLE); + _dw_mc_set_pixel_rep_clk(DW_HDMI_DISABLE); + _dw_mc_set_csc_clk(DW_HDMI_DISABLE); + + dw_mc_set_audio_sample_clk(DW_HDMI_DISABLE); + dw_mc_set_cec_clk(DW_HDMI_DISABLE); + dw_mc_set_hdcp_clk(DW_HDMI_DISABLE); } u8 dw_mc_irq_get_state(irq_sources_t irq) @@ -201,5 +205,6 @@ void dw_mc_irq_mask_all(void) dw_mc_irq_mute_source(DW_IRQ_VIDEO_PACKETIZER); dw_mc_irq_mute_source(DW_IRQ_I2C_PHY); dw_mc_irq_mute_source(DW_IRQ_AUDIO_DMA); - dw_mc_set_main_irq(0x1); + + dw_mc_set_main_irq(DW_HDMI_ENABLE); } diff --git a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_mc.h b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_mc.h index 8c2efaae5d..9c29540c4c 100644 --- a/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_mc.h +++ b/bsp/drivers/drm/sunxi_device/hardware/lowlevel_hdmi20/dw_mc.h @@ -26,21 +26,26 @@ typedef enum irq_sources { /** * @desc: main control set hdcp clock + * @bit: 0 - disable module clock + * 1 - enable module clock + */ +void dw_mc_set_hdcp_clk(u8 bit); +/** + * @desc: main control get hdcp module clock. + * @return: 0 - module clock is enable + * 1 - module clock is disable */ -void dw_mc_disable_hdcp_clock(u8 bit); - u8 dw_mc_get_hdcp_clk(void); - /** * @desc: main control set cec clock */ -void dw_mc_disable_cec_clock(u8 bit); +void dw_mc_set_cec_clk(u8 bit); /** * @desc: main control set audio sample clock */ -void dw_mc_disable_audio_sampler_clock(u8 bit); -u8 dw_mc_get_audio_sample_clock(void); +void dw_mc_set_audio_sample_clk(u8 bit); +u8 dw_mc_get_audio_sample_clk(void); /** * @desc: main control reset i2s */ diff --git a/bsp/drivers/drm/sunxi_device/sunxi_edp.c b/bsp/drivers/drm/sunxi_device/sunxi_edp.c index 18aa862843..52a757065e 100644 --- a/bsp/drivers/drm/sunxi_device/sunxi_edp.c +++ b/bsp/drivers/drm/sunxi_device/sunxi_edp.c @@ -63,6 +63,9 @@ int edp_get_edid_block(void *data, u8 *block_raw_data, struct sunxi_edp_hw_desc *edp_hw = (struct sunxi_edp_hw_desc *)(data); struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->read_edid_block) ret = ops->read_edid_block(edp_hw, block_raw_data, block_id, len); else @@ -134,6 +137,9 @@ s32 edp_hw_init_early(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->init_early) return ops->init_early(edp_hw); else @@ -144,6 +150,9 @@ s32 edp_hw_controller_init(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->init) return ops->init(edp_hw, edp_core); else @@ -171,6 +180,9 @@ s32 edp_hw_get_hotplug_state(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->get_hotplug_change && ops->get_hotplug_state) { if (ops->get_hotplug_change(edp_hw)) return ops->get_hotplug_state(edp_hw); @@ -185,6 +197,9 @@ s32 edp_hw_set_video_format(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core s32 ret = RET_OK; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->set_video_format) ret = ops->set_video_format(edp_hw, edp_core); else @@ -201,6 +216,9 @@ s32 edp_hw_set_video_timings(struct sunxi_edp_hw_desc *edp_hw, struct disp_video s32 ret = RET_OK; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->set_video_timings) ret = ops->set_video_timings(edp_hw, tmgs); else @@ -218,6 +236,9 @@ s32 edp_hw_set_transfer_config(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_c struct edp_lane_para *lane_para = &edp_core->lane_para; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->config_tu) ret = ops->config_tu(edp_hw, edp_core); else @@ -236,6 +257,9 @@ s32 edp_hw_enable(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core *edp_core { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->enable) return ops->enable(edp_hw, edp_core); else @@ -246,6 +270,9 @@ s32 edp_hw_disable(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core *edp_cor { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->disable) return ops->disable(edp_hw, edp_core); else @@ -256,6 +283,9 @@ u64 edp_source_get_max_rate(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->support_max_rate) return ops->support_max_rate(edp_hw); else @@ -266,6 +296,9 @@ u32 edp_source_get_max_lane(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->support_max_lane) return ops->support_max_lane(edp_hw); else @@ -276,6 +309,9 @@ bool edp_source_support_tps3(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_tps3) return ops->support_tps3(edp_hw); else @@ -286,6 +322,9 @@ bool edp_source_support_fast_training(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_fast_training) return ops->support_fast_training(edp_hw); else @@ -294,7 +333,10 @@ bool edp_source_support_fast_training(struct sunxi_edp_hw_desc *edp_hw) bool edp_source_support_audio(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return false; if (ops->support_audio) return ops->support_audio(edp_hw); @@ -306,6 +348,9 @@ bool edp_source_support_ssc(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_ssc) return ops->support_ssc(edp_hw); else @@ -316,6 +361,9 @@ bool edp_source_support_fec(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_fec) return ops->support_fec(edp_hw); else @@ -326,6 +374,9 @@ bool edp_source_support_psr(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_psr) return ops->support_psr(edp_hw); else @@ -336,6 +387,9 @@ bool edp_source_support_psr2(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_psr2) return ops->support_psr2(edp_hw); else @@ -346,6 +400,9 @@ bool edp_source_support_assr(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_assr) return ops->support_assr(edp_hw); else @@ -356,6 +413,9 @@ bool edp_source_support_mst(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_mst) return ops->support_mst(edp_hw); else @@ -366,6 +426,9 @@ bool edp_source_support_lane_remap(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_lane_remap) return ops->support_lane_remap(edp_hw); else @@ -376,6 +439,9 @@ bool edp_source_support_lane_invert(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_lane_invert) return ops->support_lane_invert(edp_hw); else @@ -384,7 +450,10 @@ bool edp_source_support_lane_invert(struct sunxi_edp_hw_desc *edp_hw) bool edp_source_support_hdcp1x(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + + if (ops == NULL) + return false; if (ops->support_hdcp1x) return ops->support_hdcp1x(edp_hw); @@ -394,7 +463,10 @@ bool edp_source_support_hdcp1x(struct sunxi_edp_hw_desc *edp_hw) bool edp_source_support_hardware_hdcp1x(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + + if (ops == NULL) + return false; if (ops->support_hw_hdcp1x) return ops->support_hw_hdcp1x(edp_hw); @@ -404,7 +476,10 @@ bool edp_source_support_hardware_hdcp1x(struct sunxi_edp_hw_desc *edp_hw) bool edp_source_support_hdcp2x(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + + if (ops == NULL) + return false; if (ops->support_hdcp2x) return ops->support_hdcp2x(edp_hw); @@ -414,7 +489,10 @@ bool edp_source_support_hdcp2x(struct sunxi_edp_hw_desc *edp_hw) bool edp_source_support_hardware_hdcp2x(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + + if (ops == NULL) + return false; if (ops->support_hw_hdcp2x) return ops->support_hw_hdcp2x(edp_hw); @@ -426,6 +504,9 @@ bool edp_source_support_enhance_frame(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->support_enhance_frame) return ops->support_enhance_frame(edp_hw); else @@ -494,6 +575,9 @@ s32 edp_hw_query_transfer_unit(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_c { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->query_tu_capability) return ops->query_tu_capability(edp_hw, edp_core, tmgs); else @@ -606,6 +690,9 @@ s32 edp_hw_lane_remap(struct sunxi_edp_hw_desc *edp_hw, u32 lane_id, u32 remap_i { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->lane_remap) return ops->lane_remap(edp_hw, lane_id, remap_id); else @@ -616,6 +703,9 @@ s32 edp_hw_lane_invert(struct sunxi_edp_hw_desc *edp_hw, u32 lane_id, bool inver { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->lane_invert) return ops->lane_invert(edp_hw, lane_id, invert); else @@ -630,6 +720,9 @@ void edp_hw_set_lane_para(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core * u32 lane_cnt = lane_para->lane_cnt; u32 i = 0; + if (ops == NULL) + return; + if (ops->set_lane_rate) ops->set_lane_rate(edp_hw, bit_rate); @@ -666,6 +759,9 @@ void edp_hw_set_training_para(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_co u32 param_type = edp_core->training_param_type; u32 i = 0; + if (ops == NULL) + return; + sw[0] = edp_core->lane_para.lane_sw[0]; sw[1] = edp_core->lane_para.lane_sw[1]; sw[2] = edp_core->lane_para.lane_sw[2]; @@ -1136,6 +1232,9 @@ s32 edp_main_link_setup(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core *ed s32 ret = 0; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + /* DP Link CTS need ech training start from level-0 */ edp_lane_training_para_reset(&edp_core->lane_para); @@ -1159,6 +1258,9 @@ s32 edp_hw_link_start(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->main_link_start) return ops->main_link_start(edp_hw); else @@ -1169,6 +1271,9 @@ s32 edp_hw_link_stop(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->main_link_stop) return ops->main_link_stop(edp_hw); else @@ -1195,6 +1300,9 @@ void edp_hw_irq_handler(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core *ed { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return; + if (ops->irq_handle) ops->irq_handle(edp_hw, edp_core); } @@ -1203,6 +1311,9 @@ s32 edp_hw_irq_enable(struct sunxi_edp_hw_desc *edp_hw, u32 irq_id, bool en) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->irq_enable && ops->irq_disable) { if (en) return ops->irq_enable(edp_hw, irq_id); @@ -1218,6 +1329,9 @@ s32 edp_hw_aux_read(struct sunxi_edp_hw_desc *edp_hw, s32 addr, s32 lenth, char s32 ret = 0; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->aux_read) { while (retry_cnt < 7) { ret = ops->aux_read(edp_hw, addr, lenth, buf, retry_cnt ? true : false); @@ -1250,6 +1364,9 @@ s32 edp_hw_aux_write(struct sunxi_edp_hw_desc *edp_hw, s32 addr, s32 lenth, char s32 ret = 0; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->aux_write) { while (retry_cnt < 7) { ret = ops->aux_write(edp_hw, addr, lenth, buf, retry_cnt ? true : false); @@ -1281,6 +1398,9 @@ s32 edp_hw_aux_i2c_read(struct sunxi_edp_hw_desc *edp_hw, s32 i2c_addr, s32 addr s32 ret = 0; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->aux_i2c_read) { while (retry_cnt < 7) { ret = ops->aux_i2c_read(edp_hw, i2c_addr, addr, lenth, buf, retry_cnt ? true : false); @@ -1312,6 +1432,9 @@ s32 edp_hw_aux_i2c_write(struct sunxi_edp_hw_desc *edp_hw, s32 i2c_addr, s32 add s32 ret = 0; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->aux_i2c_write) { while (retry_cnt < 7) { ret = ops->aux_i2c_write(edp_hw, i2c_addr, addr, lenth, buf, retry_cnt ? true : false); @@ -1337,29 +1460,12 @@ s32 edp_hw_aux_i2c_write(struct sunxi_edp_hw_desc *edp_hw, s32 i2c_addr, s32 add return ret; } -s32 edp_hw_audio_enable(struct sunxi_edp_hw_desc *edp_hw) -{ - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; - - if (ops->audio_enable) - return ops->audio_enable(edp_hw); - else - return RET_OK; -} - -s32 edp_hw_audio_disable(struct sunxi_edp_hw_desc *edp_hw) +s32 edp_hw_ssc_enable(struct sunxi_edp_hw_desc *edp_hw, bool enable) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; - if (ops->audio_disable) - return ops->audio_disable(edp_hw); - else + if (ops == NULL) return RET_OK; -} - -s32 edp_hw_ssc_enable(struct sunxi_edp_hw_desc *edp_hw, bool enable) -{ - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; if (ops->ssc_enable) return ops->ssc_enable(edp_hw, enable); @@ -1371,6 +1477,9 @@ bool edp_hw_ssc_is_enabled(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return false; + if (ops->ssc_is_enabled) return ops->ssc_is_enabled(edp_hw); else @@ -1381,6 +1490,9 @@ s32 edp_hw_ssc_get_mode(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->ssc_get_mode) return ops->ssc_get_mode(edp_hw); else @@ -1391,6 +1503,9 @@ s32 edp_hw_ssc_set_mode(struct sunxi_edp_hw_desc *edp_hw, u32 mode) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->ssc_set_mode) return ops->ssc_set_mode(edp_hw, mode); else @@ -1401,6 +1516,9 @@ s32 edp_hw_psr_enable(struct sunxi_edp_hw_desc *edp_hw, bool enable) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->psr_enable) return ops->psr_enable(edp_hw, enable); else @@ -1411,6 +1529,9 @@ bool edp_hw_psr_is_enabled(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->psr_is_enabled) return ops->psr_is_enabled(edp_hw); else @@ -1423,6 +1544,9 @@ s32 edp_hw_assr_enable(struct sunxi_edp_hw_desc *edp_hw, bool enable) char tmp_rx_buf[16]; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->assr_enable) { ret = ops->assr_enable(edp_hw, enable); if (ret) @@ -1451,6 +1575,9 @@ s32 edp_hw_enhance_frame_enable(struct sunxi_edp_hw_desc *edp_hw, bool enable) char tmp_rx_buf[16]; struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->enhance_frame_enable) ops->enhance_frame_enable(edp_hw, enable); @@ -1473,6 +1600,9 @@ bool edp_hw_check_controller_error(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->check_controller_error) return ops->check_controller_error(edp_hw); else @@ -1483,6 +1613,9 @@ s32 edp_hw_set_pattern(struct sunxi_edp_hw_desc *edp_hw, u32 pattern, u32 lane_c { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->set_pattern) return ops->set_pattern(edp_hw, pattern, lane_cnt); else @@ -1493,6 +1626,9 @@ void edp_hw_set_mst(struct sunxi_edp_hw_desc *edp_hw, u32 mst_cnt) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return; + if (ops->config_mst) ops->config_mst(edp_hw, mst_cnt); } @@ -1501,6 +1637,9 @@ s32 edp_hw_get_color_fmt(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->get_color_format) return ops->get_color_format(edp_hw); else @@ -1511,6 +1650,9 @@ u32 edp_hw_get_pixel_mode(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return 1; + if (ops->get_pixel_mode) return ops->get_pixel_mode(edp_hw); else @@ -1521,6 +1663,9 @@ u32 edp_hw_get_pixclk(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return 0; + if (ops->get_pixel_clk) return ops->get_pixel_clk(edp_hw); else @@ -1531,6 +1676,9 @@ u32 edp_hw_get_pattern(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return 0; + if (ops->get_pattern) return ops->get_pattern(edp_hw); else @@ -1541,6 +1689,9 @@ s32 edp_hw_get_lane_para(struct sunxi_edp_hw_desc *edp_hw, struct edp_lane_para { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return RET_OK; + if (ops->get_lane_para) return ops->get_lane_para(edp_hw, tmp_lane_para); else { @@ -1553,6 +1704,9 @@ u32 edp_hw_get_tu_size(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return 0; + if (ops->get_tu_size) return ops->get_tu_size(edp_hw); else @@ -1563,15 +1717,77 @@ u32 edp_hw_get_valid_symbol_per_tu(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + if (ops == NULL) + return 0; + if (ops->get_tu_valid_symbol) return ops->get_tu_valid_symbol(edp_hw); else return 0; } +s32 edp_hw_audio_config(struct sunxi_edp_hw_desc *edp_hw, int interface, + int chn_cnt, int data_width, int data_rate) +{ + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return RET_OK; + + if (ops->audio_config) + return ops->audio_config(edp_hw, interface, + chn_cnt, data_width, data_rate); + else + return RET_OK; + +} + +s32 edp_hw_audio_enable(struct sunxi_edp_hw_desc *edp_hw) +{ + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return RET_OK; + + if (ops->audio_enable) + return ops->audio_enable(edp_hw); + else + return RET_OK; +} + +s32 edp_hw_audio_disable(struct sunxi_edp_hw_desc *edp_hw) +{ + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return RET_OK; + + if (ops->audio_disable) + return ops->audio_disable(edp_hw); + else + return RET_OK; +} + +s32 edp_hw_audio_mute(struct sunxi_edp_hw_desc *edp_hw, + bool enable, int direction) +{ + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return RET_OK; + + if (ops->audio_mute) + return ops->audio_mute(edp_hw, enable, direction); + else + return RET_OK; +} + bool edp_hw_audio_is_enabled(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return false; if (ops->audio_is_enabled) return ops->audio_is_enabled(edp_hw); @@ -1579,52 +1795,77 @@ bool edp_hw_audio_is_enabled(struct sunxi_edp_hw_desc *edp_hw) return false; } -s32 edp_hw_get_audio_if(struct sunxi_edp_hw_desc *edp_hw) +u32 edp_hw_audio_get_max_channel(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return 0; + + if (ops->get_audio_max_channel) + return ops->get_audio_max_channel(edp_hw); + else + return 0; +} + +u32 edp_hw_get_audio_if(struct sunxi_edp_hw_desc *edp_hw) +{ + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return 0; if (ops->get_audio_if) return ops->get_audio_if(edp_hw); else - return RET_OK; + return 0; } -s32 edp_hw_audio_is_mute(struct sunxi_edp_hw_desc *edp_hw) +bool edp_hw_audio_is_mute(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return false; if (ops->audio_is_muted) return ops->audio_is_muted(edp_hw); else - return RET_OK; + return false; } -s32 edp_hw_get_audio_chn_cnt(struct sunxi_edp_hw_desc *edp_hw) +u32 edp_hw_get_audio_chn_cnt(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return 0; if (ops->get_audio_chn_cnt) return ops->get_audio_chn_cnt(edp_hw); else - return RET_OK; + return 0; } -s32 edp_hw_get_audio_data_width(struct sunxi_edp_hw_desc *edp_hw) +u32 edp_hw_get_audio_data_width(struct sunxi_edp_hw_desc *edp_hw) { - struct sunxi_edp_hw_video_ops *ops = edp_hw->video_ops; + struct sunxi_edp_hw_audio_ops *ops = edp_hw->audio_ops; + + if (ops == NULL) + return 0; if (ops->get_audio_data_width) return ops->get_audio_data_width(edp_hw); else - return RET_OK; + return 0; } s32 sunxi_edp_hw_callback_init(struct sunxi_edp_hw_desc *edp_hw) { edp_hw->video_ops = sunxi_edp_get_hw_video_ops(); - //edp_hw->audio_ops = sunxi_edp_get_hw_aduio_ops(); + edp_hw->audio_ops = sunxi_edp_get_hw_audio_ops(); edp_hw->hdcp_ops = sunxi_dp_get_hw_hdcp_ops(); return RET_OK; diff --git a/bsp/drivers/drm/sunxi_device/sunxi_edp.h b/bsp/drivers/drm/sunxi_device/sunxi_edp.h index 4b3b37ea42..dc261e261b 100644 --- a/bsp/drivers/drm/sunxi_device/sunxi_edp.h +++ b/bsp/drivers/drm/sunxi_device/sunxi_edp.h @@ -20,6 +20,7 @@ #include #include #include +#include #include "include.h" extern u32 loglevel_debug; @@ -357,6 +358,8 @@ struct edp_lane_para { struct sunxi_edp_hw_desc; struct sunxi_edp_hw_video_ops; +struct sunxi_edp_hw_audio_ops; +struct sunxi_edp_hw_hdcp_ops; @@ -452,6 +455,7 @@ struct sunxi_edp_hw_desc { u64 cur_bit_rate; struct mutex aux_lock; struct sunxi_edp_hw_video_ops *video_ops; + struct sunxi_edp_hw_audio_ops *audio_ops; struct sunxi_edp_hw_hdcp_ops *hdcp_ops; }; @@ -467,13 +471,6 @@ struct sunxi_edp_hw_video_ops { s32 (*get_color_format)(struct sunxi_edp_hw_desc *edp_hw); u32 (*get_pattern)(struct sunxi_edp_hw_desc *edp_hw); s32 (*get_lane_para)(struct sunxi_edp_hw_desc *edp_hw, struct edp_lane_para *tmp_lane_para); - s32 (*audio_is_muted)(struct sunxi_edp_hw_desc *edp_hw); - s32 (*audio_enable)(struct sunxi_edp_hw_desc *edp_hw); - s32 (*audio_disable)(struct sunxi_edp_hw_desc *edp_hw); - bool (*audio_is_enabled)(struct sunxi_edp_hw_desc *edp_hw); - s32 (*get_audio_chn_cnt)(struct sunxi_edp_hw_desc *edp_hw); - s32 (*get_audio_data_width)(struct sunxi_edp_hw_desc *edp_hw); - s32 (*get_audio_if)(struct sunxi_edp_hw_desc *edp_hw); u32 (*get_tu_valid_symbol)(struct sunxi_edp_hw_desc *edp_hw); s32 (*set_pattern)(struct sunxi_edp_hw_desc *edp_hw, u32 pattern, u32 lane_cnt); s32 (*assr_enable)(struct sunxi_edp_hw_desc *edp_hw, bool enable); @@ -517,23 +514,38 @@ struct sunxi_edp_hw_video_ops { u32 (*support_max_lane)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_tps3)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_fast_training)(struct sunxi_edp_hw_desc *edp_hw); - bool (*support_audio)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_psr)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_psr2)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_ssc)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_mst)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_fec)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_assr)(struct sunxi_edp_hw_desc *edp_hw); - bool (*support_hdcp1x)(struct sunxi_edp_hw_desc *edp_hw); - bool (*support_hw_hdcp1x)(struct sunxi_edp_hw_desc *edp_hw); - bool (*support_hdcp2x)(struct sunxi_edp_hw_desc *edp_hw); - bool (*support_hw_hdcp2x)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_lane_remap)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_lane_invert)(struct sunxi_edp_hw_desc *edp_hw); bool (*support_enhance_frame)(struct sunxi_edp_hw_desc *edp_hw); }; +struct sunxi_edp_hw_audio_ops { + bool (*support_audio)(struct sunxi_edp_hw_desc *edp_hw); + bool (*audio_is_muted)(struct sunxi_edp_hw_desc *edp_hw); + bool (*audio_is_enabled)(struct sunxi_edp_hw_desc *edp_hw); + s32 (*audio_enable)(struct sunxi_edp_hw_desc *edp_hw); + s32 (*audio_disable)(struct sunxi_edp_hw_desc *edp_hw); + s32 (*audio_mute)(struct sunxi_edp_hw_desc *edp_hw, + bool enable, int direction); + s32 (*audio_config)(struct sunxi_edp_hw_desc *edp_hw, int interface, + int chn_cnt, int data_width, int data_rate); + u32 (*get_audio_chn_cnt)(struct sunxi_edp_hw_desc *edp_hw); + u32 (*get_audio_data_width)(struct sunxi_edp_hw_desc *edp_hw); + u32 (*get_audio_if)(struct sunxi_edp_hw_desc *edp_hw); + u32 (*get_audio_max_channel)(struct sunxi_edp_hw_desc *edp_hw); +}; + struct sunxi_edp_hw_hdcp_ops { + bool (*support_hdcp1x)(struct sunxi_edp_hw_desc *edp_hw); + bool (*support_hw_hdcp1x)(struct sunxi_edp_hw_desc *edp_hw); + bool (*support_hdcp2x)(struct sunxi_edp_hw_desc *edp_hw); + bool (*support_hw_hdcp2x)(struct sunxi_edp_hw_desc *edp_hw); void (*hdcp_enable)(struct sunxi_edp_hw_desc *edp_hw, bool enable); void (*hdcp_set_mode)(struct sunxi_edp_hw_desc *edp_hw, enum dp_hdcp_mode mode); u64 (*hdcp1_get_an)(struct sunxi_edp_hw_desc *edp_hw); @@ -679,7 +691,6 @@ u32 edp_source_get_max_lane(struct sunxi_edp_hw_desc *edp_hw); bool edp_source_support_tps3(struct sunxi_edp_hw_desc *edp_hw); bool edp_source_support_fast_training(struct sunxi_edp_hw_desc *edp_hw); -bool edp_source_support_audio(struct sunxi_edp_hw_desc *edp_hw); bool edp_source_support_ssc(struct sunxi_edp_hw_desc *edp_hw); bool edp_source_support_psr(struct sunxi_edp_hw_desc *edp_hw); bool edp_source_support_psr2(struct sunxi_edp_hw_desc *edp_hw); @@ -697,7 +708,6 @@ bool edp_hw_check_controller_error(struct sunxi_edp_hw_desc *edp_hw); bool edp_hw_ssc_is_enabled(struct sunxi_edp_hw_desc *edp_hw); bool edp_hw_psr_is_enabled(struct sunxi_edp_hw_desc *edp_hw); -bool edp_hw_audio_is_enabled(struct sunxi_edp_hw_desc *edp_hw); void edp_hw_set_reg_base(struct sunxi_edp_hw_desc *edp_hw, void __iomem *base); void edp_hw_set_top_base(struct sunxi_edp_hw_desc *edp_hw, void __iomem *base); @@ -736,17 +746,24 @@ u32 edp_hw_get_pattern(struct sunxi_edp_hw_desc *edp_hw); s32 edp_hw_get_lane_para(struct sunxi_edp_hw_desc *edp_hw, struct edp_lane_para *tmp_lane_para); u32 edp_hw_get_tu_size(struct sunxi_edp_hw_desc *edp_hw); u32 edp_hw_get_valid_symbol_per_tu(struct sunxi_edp_hw_desc *edp_hw); -s32 edp_hw_get_audio_if(struct sunxi_edp_hw_desc *edp_hw); -s32 edp_hw_audio_is_mute(struct sunxi_edp_hw_desc *edp_hw); -s32 edp_hw_get_audio_chn_cnt(struct sunxi_edp_hw_desc *edp_hw); -s32 edp_hw_get_audio_data_width(struct sunxi_edp_hw_desc *edp_hw); s32 edp_hw_set_video_format(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core *edp_core); s32 edp_hw_set_video_timings(struct sunxi_edp_hw_desc *edp_hw, struct disp_video_timings *tmgs); s32 edp_hw_set_transfer_config(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core *edp_core); void edp_hw_set_mst(struct sunxi_edp_hw_desc *edp_hw, u32 mst_cnt); s32 edp_hw_query_lane_capability(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core *edp_core, struct disp_video_timings *tmgs); - +bool edp_source_support_audio(struct sunxi_edp_hw_desc *edp_hw); +bool edp_hw_audio_is_enabled(struct sunxi_edp_hw_desc *edp_hw); +bool edp_hw_audio_is_mute(struct sunxi_edp_hw_desc *edp_hw); +s32 edp_hw_audio_enable(struct sunxi_edp_hw_desc *edp_hw); +s32 edp_hw_audio_disable(struct sunxi_edp_hw_desc *edp_hw); +u32 edp_hw_get_audio_if(struct sunxi_edp_hw_desc *edp_hw); +u32 edp_hw_get_audio_chn_cnt(struct sunxi_edp_hw_desc *edp_hw); +u32 edp_hw_get_audio_data_width(struct sunxi_edp_hw_desc *edp_hw); +u32 edp_hw_audio_get_max_channel(struct sunxi_edp_hw_desc *edp_hw); +s32 edp_hw_audio_config(struct sunxi_edp_hw_desc *edp_hw, int interface, + int chn_cnt, int data_width, int data_rate); +s32 edp_hw_audio_mute(struct sunxi_edp_hw_desc *edp_hw, bool enable, int direction); s32 edp_main_link_setup(struct sunxi_edp_hw_desc *edp_hw, struct edp_tx_core *edp_core); s32 sunxi_edp_hw_callback_init(struct sunxi_edp_hw_desc *edp_hw); @@ -768,6 +785,7 @@ s32 sunxi_edp_hw_callback_init(struct sunxi_edp_hw_desc *edp_hw); #if IS_ENABLED(CONFIG_AW_DRM_EDP_CONTROLLER_USED) struct sunxi_edp_hw_video_ops *sunxi_edp_get_hw_video_ops(void); +struct sunxi_edp_hw_audio_ops *sunxi_edp_get_hw_audio_ops(void); #if IS_ENABLED(CONFIG_AW_DRM_DP_HDCP) /* hdcp*/ @@ -809,6 +827,12 @@ static inline struct sunxi_edp_hw_video_ops *sunxi_edp_get_hw_video_ops(void) EDP_ERR("there is no controller selected for sunxi edp!\n"); return NULL; } + +static inline struct sunxi_edp_hw_audio_ops *sunxi_edp_get_hw_audio_ops(void) +{ + EDP_ERR("there is no controller selected for sunxi edp!\n"); + return NULL; +} #endif #endif /*End of file*/ diff --git a/bsp/drivers/drm/sunxi_device/sunxi_edp_hdcp.c b/bsp/drivers/drm/sunxi_device/sunxi_edp_hdcp.c index 950b2142fa..8cb8fcb15e 100644 --- a/bsp/drivers/drm/sunxi_device/sunxi_edp_hdcp.c +++ b/bsp/drivers/drm/sunxi_device/sunxi_edp_hdcp.c @@ -32,6 +32,9 @@ static u64 dptx_hdcp1_hw_get_an(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + if (ops == NULL) + return 0; + if (ops->hdcp1_get_an) return ops->hdcp1_get_an(edp_hw); else @@ -42,6 +45,9 @@ static u64 dptx_hdcp1_hw_get_aksv(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + if (ops == NULL) + return 0; + if (ops->hdcp1_get_aksv) return ops->hdcp1_get_aksv(edp_hw); else @@ -52,6 +58,9 @@ static void dptx_hdcp1_hw_write_bksv(struct sunxi_edp_hw_desc *edp_hw, u64 bksv) { struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + if (ops == NULL) + return; + if (ops->hdcp1_write_bksv) return ops->hdcp1_write_bksv(edp_hw, bksv); } @@ -60,6 +69,9 @@ static u64 dptx_hdcp1_hw_calculate_km(struct sunxi_edp_hw_desc *edp_hw, u64 bksv { struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + if (ops == NULL) + return 0; + if (ops->hdcp1_cal_km) return ops->hdcp1_cal_km(edp_hw, bksv); else @@ -70,6 +82,9 @@ static u32 dptx_hdcp1_hw_calculate_r0(struct sunxi_edp_hw_desc *edp_hw, u64 an, { struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + if (ops == NULL) + return 0; + if (ops->hdcp1_cal_r0) return ops->hdcp1_cal_r0(edp_hw, an, km); else @@ -80,6 +95,9 @@ static u64 dptx_hdcp1_hw_get_m0(struct sunxi_edp_hw_desc *edp_hw) { struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + if (ops == NULL) + return 0; + if (ops->hdcp1_get_m0) return ops->hdcp1_get_m0(edp_hw); else @@ -90,6 +108,9 @@ static void dptx_hdcp1_hw_encrypt_enable(struct sunxi_edp_hw_desc *edp_hw, bool { struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + if (ops == NULL) + return; + if (ops->hdcp1_encrypt_enable) ops->hdcp1_encrypt_enable(edp_hw, enable); } @@ -98,6 +119,9 @@ static void dptx_hdcp_hw_enable(struct sunxi_edp_hw_desc *edp_hw, bool enable) { struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + if (ops == NULL) + return; + if (ops->hdcp_enable) ops->hdcp_enable(edp_hw, enable); } @@ -106,6 +130,9 @@ void dptx_hdcp_hw_set_mode(struct sunxi_edp_hw_desc *edp_hw, enum dp_hdcp_mode m { struct sunxi_edp_hw_hdcp_ops *ops = edp_hw->hdcp_ops; + if (ops == NULL) + return; + if (ops->hdcp_set_mode) ops->hdcp_set_mode(edp_hw, mode); } diff --git a/bsp/drivers/drm/sunxi_device/sunxi_hdmi.c b/bsp/drivers/drm/sunxi_device/sunxi_hdmi.c index 03dde7443e..ca292385e6 100644 --- a/bsp/drivers/drm/sunxi_device/sunxi_hdmi.c +++ b/bsp/drivers/drm/sunxi_device/sunxi_hdmi.c @@ -8,7 +8,7 @@ * License version 2. This program is licensed "as is" without any * warranty of any kind, whether express or implied. ******************************************************************************/ - +#include #include #include @@ -62,13 +62,23 @@ struct sunxi_hdmi_plat_s sun55i_hdmi = { struct sunxi_hdmi_plat_s sun60i_hdmi = { .version = HDMI_SUN60I_W2_P1, - .use_top_phy = 0x1, + .use_top_phy = SUNXI_HDMI_ENABLE, .phy_func.phy_init = snps_phy_init, .phy_func.phy_config = snps_phy_config, .phy_func.phy_disconfig = snps_phy_disconfig, .phy_func.phy_read = snps_phy_read, .phy_func.phy_write = snps_phy_write, .phy_func.phy_dump = snps_phy_dump, + + /* config sun60i res cal and register and bitmask */ + .need_res_cal = SUNXI_HDMI_ENABLE, + .rescal_regs.rescal_ctrl_pa = 0x03000160, + .rescal_regs.bit_hdmi_res_sel = (u32)BIT(12), + .rescal_regs.bit_rescal_mode = (u32)BIT(2), + .rescal_regs.bit_cal_ana_en = (u32)BIT(1), + .rescal_regs.bit_cal_en = (u32)BIT(0), + .rescal_regs.res0_ctrl_pa = 0x03000164, + .rescal_regs.res0_ctrl_bitmask = (u32)GENMASK(31, 24), }; struct sunxi_hdmi_s *sunxi_hdmi; @@ -293,19 +303,17 @@ int sunxi_hdcp2x_fw_loading(const u8 *data, size_t size) int sunxi_hdcp1x_config(u8 state) { - if (state) { - dw_hdcp_config_init(); + if (state) return dw_hdcp1x_enable(); - } else + else return dw_hdcp1x_disable(); } int sunxi_hdcp2x_config(u8 state) { - if (state) { - dw_hdcp_config_init(); + if (state) return dw_hdcp2x_enable(); - } else + else return dw_hdcp2x_disable(); } @@ -970,6 +978,45 @@ int sunxi_hdmi_set_disp_mode(struct drm_display_mode *mode) return -1; } +static int _sunxi_hdmi_board_init(struct sunxi_hdmi_s *hdmi) +{ + u8 res_src = hdmi->resistor_src; + u8 rescal_en = hdmi->plat_data->need_res_cal; + struct sunxi_hdmi_rescal_s *res_reg = &hdmi->plat_data->rescal_regs; + + void __iomem *reg_addr; + + if (!rescal_en) { + hdmi_trace("this plat not need use resistance calibration\n"); + return 0; + } + + if (res_src == 0x1) { + reg_addr = ioremap(res_reg->rescal_ctrl_pa, 4); + writel(readl(reg_addr) | res_reg->bit_hdmi_res_sel, reg_addr); + iounmap(reg_addr); + + reg_addr = ioremap(res_reg->res0_ctrl_pa, 4); + writel(readl(reg_addr) & (~res_reg->res0_ctrl_bitmask), reg_addr); + iounmap(reg_addr); + } else { + reg_addr = ioremap(res_reg->rescal_ctrl_pa, 4); + + writel((readl(reg_addr) & (~res_reg->bit_cal_en)), reg_addr); + writel((readl(reg_addr) & (~res_reg->bit_hdmi_res_sel)), reg_addr); + writel((readl(reg_addr) | (res_reg->bit_cal_ana_en)), reg_addr); + writel((readl(reg_addr) | (res_reg->bit_cal_en)), reg_addr); + + udelay(200); + + writel((readl(reg_addr) & (~res_reg->bit_cal_ana_en)), reg_addr); + writel((readl(reg_addr) & (~res_reg->bit_cal_en)), reg_addr); + + iounmap(reg_addr); + } + return 0; +} + static const struct of_device_id hdmi_plat_match[] = { { .compatible = "arm,sun8iw20p1", .data = &sun8i_hdmi }, { .compatible = "arm,sun50iw9p1", .data = &sun50i_hdmi }, @@ -1002,6 +1049,11 @@ int sunxi_hdmi_init(struct sunxi_hdmi_s *hdmi) return -1; } + if (!hdmi->smooth_boot) { + _sunxi_hdmi_board_init(hdmi); + hdmi_trace("sunxi hdmi board init done\n"); + } + /* bind phy ops */ hdmi->dw_hdmi.phy_ext = &hdmi->plat_data->phy_func; hdmi->dw_hdmi.dev = hdmi->dev; diff --git a/bsp/drivers/drm/sunxi_device/sunxi_hdmi.h b/bsp/drivers/drm/sunxi_device/sunxi_hdmi.h index 300be31291..e0d5ed9a98 100644 --- a/bsp/drivers/drm/sunxi_device/sunxi_hdmi.h +++ b/bsp/drivers/drm/sunxi_device/sunxi_hdmi.h @@ -149,9 +149,24 @@ enum HDMI_CEA_VIC { /****************************************************************** * @desc: sunxi hdmi level struct *****************************************************************/ +struct sunxi_hdmi_rescal_s { + unsigned long rescal_ctrl_pa; + u32 bit_hdmi_res_sel; + u32 bit_rescal_mode; + u32 bit_cal_ana_en; + u32 bit_cal_en; + + unsigned long res0_ctrl_pa; + u32 res0_ctrl_bitmask; +}; + struct sunxi_hdmi_plat_s { unsigned char version; unsigned char use_top_phy; + /* resistance calibration */ + unsigned char need_res_cal; + struct sunxi_hdmi_rescal_s rescal_regs; + struct dw_phy_ops_s phy_func; }; @@ -162,6 +177,7 @@ struct sunxi_hdmi_s { u8 smooth_boot; u8 clock_src; + u8 resistor_src; uintptr_t reg_base; struct sunxi_hdmi_plat_s *plat_data; diff --git a/bsp/drivers/drm/sunxi_device/sunxi_tcon.c b/bsp/drivers/drm/sunxi_device/sunxi_tcon.c index 2621a3d2d6..5840e4d02f 100644 --- a/bsp/drivers/drm/sunxi_device/sunxi_tcon.c +++ b/bsp/drivers/drm/sunxi_device/sunxi_tcon.c @@ -634,13 +634,14 @@ int sunxi_tcon_hdmi_mode_init(struct device *dev) return 0; } - /* calculate actual pixel clock */ - pclk = p_timing->pixel_clk * (p_timing->pixel_repeat + 1); - if (format == DISP_CSC_TYPE_YUV420) - pclk /= 2; - _sunxi_tcon_hdmi_set_rate(hwtcon, pclk); - + /* if sw enable. will not handle tcon clock and timing config */ if (!sw_enable) { + /* calculate actual pixel clock */ + pclk = p_timing->pixel_clk * (p_timing->pixel_repeat + 1); + if (format == DISP_CSC_TYPE_YUV420) + pclk /= 2; + _sunxi_tcon_hdmi_set_rate(hwtcon, pclk); + ret = _sunxi_tcon_hdmi_config(hwtcon, de_id, p_timing, format); if (ret != 0) { DRM_ERROR("tcon hdmi config failed\n"); diff --git a/bsp/drivers/drm/sunxi_drm_drv.c b/bsp/drivers/drm/sunxi_drm_drv.c index d004da4fd2..40731d24ee 100644 --- a/bsp/drivers/drm/sunxi_drm_drv.c +++ b/bsp/drivers/drm/sunxi_drm_drv.c @@ -53,6 +53,7 @@ struct display_boot_info { unsigned int tcon_id; unsigned int connector_type;//DRM_MODE_CONNECTOR_ unsigned int hw_id;//DRM_MODE_CONNECTOR_ + struct drm_display_mode mode; /* unsigned int mode; unsigned int format; unsigned int bits; @@ -591,9 +592,12 @@ static int get_boot_display_info(struct drm_device *drm) { struct sunxi_drm_private *pri = to_sunxi_drm_private(drm); struct display_boot_info *info; + struct drm_display_mode *mode; struct device_node *routing; + struct device_node *mode_node; char name[16]; int i, ret; + u32 read_val = 0; INIT_LIST_HEAD(&pri->priv->boot_info_head); for (i = 0; ; i++) { @@ -613,15 +617,49 @@ static int get_boot_display_info(struct drm_device *drm) ret = of_property_read_u32_array(routing, "route", &info->de_id, 4); if (ret) { - kfree(info); of_node_put(routing); + kfree(info); + return 0; + } + + /* parse add mode info */ + mode = &info->mode; + mode_node = of_get_child_by_name(routing, "mode"); + if (!mode_node) { + DRM_ERROR("find mode node failed\n"); return 0; } +#define of_mode_read(name, value) \ + do { \ + of_property_read_u32(mode_node, name, &read_val); \ + value = read_val; \ + } while (0) + + of_mode_read("clock", mode->clock); + of_mode_read("hdisplay", mode->hdisplay); + of_mode_read("vdisplay", mode->vdisplay); + of_mode_read("hsync_start", mode->hsync_start); + of_mode_read("vsync_start", mode->vsync_start); + of_mode_read("hsync_end", mode->hsync_end); + of_mode_read("vsync_end", mode->vsync_end); + of_mode_read("htotal", mode->htotal); + of_mode_read("vtotal", mode->vtotal); + of_mode_read("vscan", mode->vscan); + of_mode_read("flags", mode->flags); + of_mode_read("hskew", mode->hskew); + of_mode_read("type", mode->type); +#undef of_mode_read + + drm_mode_set_name(mode); + + DRM_DEBUG_DRIVER("boot mode: " DRM_MODE_FMT "\n", DRM_MODE_ARG(mode)); + list_add_tail(&info->list, &pri->priv->boot_info_head); + + of_node_put(mode_node); of_node_put(routing); } - return 0; } @@ -635,7 +673,7 @@ static int init_connecting(struct drm_device *drm, struct drm_crtc **crtcs, unsi struct drm_connector *connector_ = NULL; struct display_boot_info *info; struct drm_display_mode *mode = NULL; - int i, id, modes_count, init_cnt = 0; + int i, id, modes_count, init_cnt = 0, mode_found = 0; if (!crtc_cnt || !connector_cnt) { DRM_ERROR("connector or crtc null\n"); @@ -668,9 +706,20 @@ static int init_connecting(struct drm_device *drm, struct drm_crtc **crtcs, unsi info->hw_id == sdrm->hw_id) { mutex_lock(&drm->mode_config.mutex); modes_count = connectors[i]->funcs->fill_modes(connectors[i], 8192, 8192); - //DRM_INFO("%s found mode %d\n", __FUNCTION__, modes_count); - //TODO pick mode - mode = list_first_entry_or_null(&connectors[i]->modes, struct drm_display_mode, head); + if (!modes_count) + break; + + list_for_each_entry(mode, &connectors[i]->modes, head) { + if (mode && drm_mode_equal(&info->mode, mode)) { + mode_found = 1; + break; + } + }; + if (mode_found) + mode = &info->mode; + else + mode = list_first_entry_or_null(&connectors[i]->modes, struct drm_display_mode, head); + DRM_DEBUG_DRIVER("%s use mode %dx%d\n", __FUNCTION__, mode->hdisplay, mode->vdisplay); mutex_unlock(&drm->mode_config.mutex); if (mode) { diff --git a/bsp/drivers/drm/sunxi_drm_edp.c b/bsp/drivers/drm/sunxi_drm_edp.c index 2a533d08f9..dcc7033860 100644 --- a/bsp/drivers/drm/sunxi_drm_edp.c +++ b/bsp/drivers/drm/sunxi_drm_edp.c @@ -36,6 +36,7 @@ #include #include #include +#include #include "sunxi_device/sunxi_edp.h" #include "sunxi_device/sunxi_tcon.h" @@ -55,6 +56,8 @@ #define CEA_YCC444_MASK (1 << 5) /* Version3 */ #define CEA_YCC422_MASK (1 << 4) /* Version3 */ +#define SUNXI_EDP_CODEC_DRV_NAME "sunxi-snd-codec-av" + u32 loglevel_debug; struct edp_debug { @@ -92,6 +95,7 @@ struct sunxi_drm_edp { struct class *edp_class; struct device *edp_class_dev; struct device *dev; + struct platform_device *audio_pdev; struct phy *dp_phy; struct phy *aux_phy; struct phy *combo_phy; @@ -4120,6 +4124,79 @@ int sunxi_edp_init_sysfs(struct sunxi_drm_edp *drm_edp) return ret; } +static int sunxi_edp_audio_hw_params(struct device *dev, void *data, + struct hdmi_codec_daifmt *daifmt, + struct hdmi_codec_params *params) +{ + struct sunxi_drm_edp *drm_edp = dev_get_drvdata(dev); + struct sunxi_edp_hw_desc *edp_hw = &drm_edp->edp_hw; + int channels = params->channels; + int sample_rate = params->sample_rate; + int sample_width = params->sample_width; + int interface = daifmt->fmt; + + edp_hw_audio_config(edp_hw, interface, channels, + sample_width, sample_rate); + + return 0; +} + +static int sunxi_edp_audio_mute_stream(struct device *dev, void *data, + bool enable, int direction) +{ + struct sunxi_drm_edp *drm_edp = dev_get_drvdata(dev); + struct sunxi_edp_hw_desc *edp_hw = &drm_edp->edp_hw; + + edp_hw_audio_mute(edp_hw, enable, direction); + + return 0; +} + +static int sunxi_edp_audio_startup(struct device *dev, void *data) +{ + struct sunxi_drm_edp *drm_edp = dev_get_drvdata(dev); + struct sunxi_edp_hw_desc *edp_hw = &drm_edp->edp_hw; + + edp_hw_audio_enable(edp_hw); + + return 0; +} + +static void sunxi_edp_audio_shutdown(struct device *dev, void *data) +{ + struct sunxi_drm_edp *drm_edp = dev_get_drvdata(dev); + struct sunxi_edp_hw_desc *edp_hw = &drm_edp->edp_hw; + + edp_hw_audio_disable(edp_hw); +} + +static const struct hdmi_codec_ops sunxi_edp_audio_codec_ops = { + .hw_params = sunxi_edp_audio_hw_params, + .audio_startup = sunxi_edp_audio_startup, + .audio_shutdown = sunxi_edp_audio_shutdown, + .mute_stream = sunxi_edp_audio_mute_stream, +}; + +static int sunxi_edp_register_audio_driver(struct device *dev) +{ + struct sunxi_drm_edp *drm_edp = dev_get_drvdata(dev); + struct hdmi_codec_pdata codec_data = { + .ops = &sunxi_edp_audio_codec_ops, + .max_i2s_channels = edp_hw_audio_get_max_channel(&drm_edp->edp_hw), + .i2s = 1, + .spdif = 1, + .data = drm_edp, + }; + + drm_edp->audio_pdev = platform_device_register_data(dev, + SUNXI_EDP_CODEC_DRV_NAME, + PLATFORM_DEVID_AUTO, + &codec_data, + sizeof(codec_data)); + + return PTR_ERR_OR_ZERO(drm_edp->audio_pdev); +} + static int sunxi_drm_edp_bind(struct device *dev, struct device *master, void *data) { @@ -4129,6 +4206,8 @@ static int sunxi_drm_edp_bind(struct device *dev, struct device *master, struct device_node *panel_np; struct drm_device *drm = (struct drm_device *)data; struct device *tcon_tv_dev = NULL; + struct edp_tx_cap *src_cap; + const struct of_device_id *match; int ret, tcon_id, conn_type, conn_id; @@ -4224,6 +4303,10 @@ static int sunxi_drm_edp_bind(struct device *dev, struct device *master, goto OUT; } + src_cap = &drm_edp->source_cap; + if (src_cap->audio_support) + sunxi_edp_register_audio_driver(dev); + EDP_DRV_DBG("edp bind finish!\n"); return RET_OK; diff --git a/bsp/drivers/drm/sunxi_drm_hdmi.c b/bsp/drivers/drm/sunxi_drm_hdmi.c index c45d7cde3a..cd5328fbe0 100644 --- a/bsp/drivers/drm/sunxi_drm_hdmi.c +++ b/bsp/drivers/drm/sunxi_drm_hdmi.c @@ -156,6 +156,7 @@ struct sunxi_hdmi_ctrl_s { unsigned int drv_dts_power_cnt; unsigned int drv_dts_clk_src; unsigned int drv_dts_ddc_index; + unsigned int drv_dts_res_src; /* hdcp control state */ int drv_hdcp_clock; @@ -1959,6 +1960,8 @@ static ssize_t _sunxi_hdmi_sysfs_hdmi_source_show(struct device *dev, hdmi->hdmi_ctrl.drv_dts_hdcp2x ? "enable" : "disable"); n += sprintf(buf + n, " - clk_source : [%s]\n", hdmi->hdmi_ctrl.drv_dts_clk_src ? "ccmu" : "phypll"); + n += sprintf(buf + n, " - resistor : [%s]\n", + hdmi->hdmi_ctrl.drv_dts_res_src ? "onboard" : "onchip"); n += sprintf(buf + n, "[drm state]\n"); n += sprintf(buf + n, " - enable : [%s]\n", @@ -2575,6 +2578,7 @@ static int _sunxi_drm_hdmi_get_modes(struct drm_connector *connector) static enum drm_mode_status _sunxi_drm_hdmi_mode_valid( struct drm_connector *connector, struct drm_display_mode *mode) { + int rate = drm_mode_vrefresh(mode); /* check frame rate support */ @@ -2869,6 +2873,10 @@ static int __sunxi_hdmi_init_dts(struct sunxi_drm_hdmi *hdmi) ret = of_property_read_u32(node, "hdmi_clock_source", &value); hdmi->hdmi_ctrl.drv_dts_clk_src = (ret != 0x0) ? 0x0 : value; + /* if dts not set, default use external resistor */ + ret = of_property_read_u32(node, "hdmi_resistor_select", &value); + hdmi->hdmi_ctrl.drv_dts_res_src = (ret != 0x0) ? 0x1 : value; + /* if dts not set, default use 0x1F */ ret = of_property_read_u32(node, "hdmi_ddc_index", &value); hdmi->hdmi_ctrl.drv_dts_ddc_index = (ret != 0x0) ? 0x1F : value; @@ -3157,7 +3165,8 @@ static int _sunxi_hdmi_init_drv(struct sunxi_drm_hdmi *hdmi) hdmi->hdmi_core.i2c_adap = &hdmi->i2c_adap; hdmi->hdmi_core.connect = &hdmi->sdrm.connector; hdmi->hdmi_core.clock_src = hdmi->hdmi_ctrl.drv_dts_clk_src; - hdmi->hdmi_core.smooth_boot = hdmi->hdmi_ctrl.drv_boot_enable; + hdmi->hdmi_core.resistor_src = hdmi->hdmi_ctrl.drv_dts_res_src; + hdmi->hdmi_core.smooth_boot = hdmi->hdmi_ctrl.drv_boot_enable; ret = sunxi_hdmi_init(&hdmi->hdmi_core); if (ret != 0) { hdmi_err("sunxi hdmi init core failed!!!\n"); diff --git a/bsp/drivers/gpu/panfrost/panfrost_drv.c b/bsp/drivers/gpu/panfrost/panfrost_drv.c index d9bf5c4cea..14def35b45 100644 --- a/bsp/drivers/gpu/panfrost/panfrost_drv.c +++ b/bsp/drivers/gpu/panfrost/panfrost_drv.c @@ -695,7 +695,19 @@ static struct platform_driver panfrost_driver = { .of_match_table = dt_match, }, }; -module_platform_driver(panfrost_driver); + +static int __init panfrost_driver_init(void) +{ + return platform_driver_register(&panfrost_driver); +} + +static void __exit panfrost_driver_exit(void) +{ + platform_driver_unregister(&panfrost_driver); +} + +late_initcall(panfrost_driver_init); +module_exit(panfrost_driver_exit); MODULE_AUTHOR("Panfrost Project Developers"); MODULE_DESCRIPTION("Panfrost DRM Driver"); diff --git a/bsp/drivers/net/wireless/Kconfig b/bsp/drivers/net/wireless/Kconfig index 0c73851645..2b9f5fd797 100644 --- a/bsp/drivers/net/wireless/Kconfig +++ b/bsp/drivers/net/wireless/Kconfig @@ -4,10 +4,20 @@ menu "Wireless LAN" if WLAN +source "bsp/drivers/net/wireless/bcmdhd/Kconfig" +source "bsp/drivers/net/wireless/rtl8188fu/Kconfig" +source "bsp/drivers/net/wireless/rtl8723cs/Kconfig" +source "bsp/drivers/net/wireless/rtl8723ds/Kconfig" +source "bsp/drivers/net/wireless/rtl8723du/Kconfig" +source "bsp/drivers/net/wireless/rtl8822bs/Kconfig" +source "bsp/drivers/net/wireless/rtl8822cu/Kconfig" +source "bsp/drivers/net/wireless/rtl8852bs/Kconfig" source "bsp/drivers/net/wireless/xr819/Kconfig" source "bsp/drivers/net/wireless/xr829/Kconfig" +source "bsp/drivers/net/wireless/uwe5622/Kconfig" source "bsp/drivers/net/wireless/aic8800/Kconfig" - +source "bsp/drivers/net/wireless/atbm6023is/Kconfig" +source "bsp/drivers/net/wireless/ssv6158/Kconfig" endif endmenu diff --git a/bsp/drivers/net/wireless/Makefile b/bsp/drivers/net/wireless/Makefile index 99ca07462d..1de190ca11 100644 --- a/bsp/drivers/net/wireless/Makefile +++ b/bsp/drivers/net/wireless/Makefile @@ -3,6 +3,17 @@ # Makefile for the Linux wirless network device drivers. # +obj-$(CONFIG_BCMDHD) += bcmdhd/ +obj-$(CONFIG_RTL8188FU) += rtl8188fu/ +obj-$(CONFIG_RTL8723CS) += rtl8723cs/ +obj-$(CONFIG_RTL8723DS) += rtl8723ds/ +obj-$(CONFIG_RTL8723DU) += rtl8723du/ +obj-$(CONFIG_RTL8822BS) += rtl8822bs/ +obj-$(CONFIG_RTL8822CU) += rtl8822cu/ +obj-$(CONFIG_RTL8852BS) += rtl8852bs/ obj-$(CONFIG_XR819_WLAN) += xr819/ obj-$(CONFIG_XR829_WLAN) += xr829/ +obj-$(CONFIG_SPARD_WLAN_SUPPORT) += uwe5622/ obj-$(CONFIG_AIC_WLAN_SUPPORT) += aic8800/ +obj-$(CONFIG_ATBM_WIRELESS) += atbm6023is/ +obj-$(CONFIG_SSV6158) += ssv6158/ diff --git a/bsp/drivers/npu/aw_nna_vip/linux/allwinner/gc_vip_kernel_drv_platform.c b/bsp/drivers/npu/aw_nna_vip/linux/allwinner/gc_vip_kernel_drv_platform.c index 80ae27525f..694e4662ef 100644 --- a/bsp/drivers/npu/aw_nna_vip/linux/allwinner/gc_vip_kernel_drv_platform.c +++ b/bsp/drivers/npu/aw_nna_vip/linux/allwinner/gc_vip_kernel_drv_platform.c @@ -83,7 +83,7 @@ static vip_status_e npu_regulator_enable(struct device_node *node) /* npu-regulator para : NPU Regulator Control. * if 1, use npu set vol; if 0, uboot set npu vol. */ - err = of_property_read_u32_index(node, "npu-regulator", 0, &npu_regulator); + err = of_property_read_u32_index(node, "npu-setvol", 0, &npu_regulator); if (err != 0) PRINTK("Get NPU Regulator Control FAIL!\n"); diff --git a/bsp/drivers/pinctrl/pinctrl-sun55iw3-r.c b/bsp/drivers/pinctrl/pinctrl-sun55iw3-r.c index d6be4d1648..30fe280d8a 100644 --- a/bsp/drivers/pinctrl/pinctrl-sun55iw3-r.c +++ b/bsp/drivers/pinctrl/pinctrl-sun55iw3-r.c @@ -224,7 +224,8 @@ static const struct sunxi_pinctrl_desc sun55iw3_r_pinctrl_data = { .irq_banks = ARRAY_SIZE(sun55iw3_r_irq_bank_map), .irq_bank_map = sun55iw3_r_irq_bank_map, .pin_base = SUNXI_PIN_BASE('L'), - .hw_type = SUNXI_PCTL_HW_TYPE_1, + .hw_type = SUNXI_PCTL_HW_TYPE_6, + .io_bias_cfg_variant = BIAS_VOLTAGE_PIO_POW_MODE_CTL_V2, }; static int sun55iw3_r_pinctrl_probe(struct platform_device *pdev) @@ -255,4 +256,4 @@ postcore_initcall(sun55iw3_r_pio_init); MODULE_DESCRIPTION("Allwinner sun55iw3 R_PIO pinctrl driver"); MODULE_LICENSE("GPL"); MODULE_AUTHOR(""); -MODULE_VERSION("1.1.4"); +MODULE_VERSION("1.1.5"); diff --git a/bsp/drivers/pinctrl/pinctrl-sunxi.c b/bsp/drivers/pinctrl/pinctrl-sunxi.c index 4d7d07ed83..91e60973c7 100644 --- a/bsp/drivers/pinctrl/pinctrl-sunxi.c +++ b/bsp/drivers/pinctrl/pinctrl-sunxi.c @@ -201,6 +201,31 @@ struct sunxi_pinctrl_hw_info sunxi_pinctrl_hw_info[SUNXI_PCTL_HW_TYPE_CNT] = { .power_mode_reverse = false, .power_mode_detect = true, }, + { + .initial_bank_offset = 0x0, + .mux_regs_offset = 0x0, + .data_regs_offset = 0x10, + .dlevel_regs_offset = 0x14, + .bank_mem_size = 0x30, + .pull_regs_offset = 0x24, + .dlevel_pins_per_reg = 8, + .dlevel_pins_bits = 4, + .dlevel_pins_mask = 0xF, + .irq_mux_val = 0xE, + .irq_cfg_reg = 0x200, + .irq_ctrl_reg = 0x210, + .irq_status_reg = 0x214, + .irq_debounce_reg = 0x218, + .irq_mem_base = 0x200, + .irq_mem_size = 0x20, + .irq_mem_used = 0x20, + .power_mode_sel_reg = 0x340, + .power_mode_ctrl_reg = 0x344, + .power_mode_val_reg = 0x348, + .pio_pow_ctrl_reg = 0x350, + .power_mode_reverse = true, + .power_mode_detect = true, + }, }; EXPORT_SYMBOL_GPL(sunxi_pinctrl_hw_info); @@ -641,6 +666,147 @@ static const struct pinctrl_ops sunxi_pctrl_ops = { .get_group_pins = sunxi_pctrl_get_group_pins, }; +DEFINE_SPINLOCK(sun55iw3_pinctrl_lock); + +#if IS_ENABLED(CONFIG_ARCH_SUN55IW3) +static const u32 sun55iw3_bank_base[] = { + SUNXI_BANK_OFFSET('B', 'A'), + SUNXI_BANK_OFFSET('C', 'A'), + SUNXI_BANK_OFFSET('D', 'A'), + SUNXI_BANK_OFFSET('E', 'A'), + SUNXI_BANK_OFFSET('F', 'A'), + SUNXI_BANK_OFFSET('G', 'A'), + SUNXI_BANK_OFFSET('H', 'A'), + SUNXI_BANK_OFFSET('I', 'A'), + SUNXI_BANK_OFFSET('J', 'A'), + SUNXI_BANK_OFFSET('K', 'A'), +}; +/* Describe which bank use vcc-io */ +static const u32 sun55iw3_vccio_banks[] = { + SUNXI_BANK_OFFSET('B', 'A'), + SUNXI_BANK_OFFSET('H', 'A'), +}; + +static const u32 sun55iw3_r_bank_base[] = { + SUNXI_BANK_OFFSET('L', 'L'), + SUNXI_BANK_OFFSET('M', 'L'), +}; + +static u32 sun55iw3_vccio_sel_map(bool is_cpus_gpio, int bank) +{ + int i; + + if (is_cpus_gpio) + return bank; + + for (i = 0; i < ARRAY_SIZE(sun55iw3_vccio_banks); i++) { + if (sun55iw3_vccio_banks[i] == bank) + return 12; + } + return bank; +} + +static u32 sun55iw3_vccio_val_map(bool is_cpus_gpio, int bank) +{ + int i; + + if (is_cpus_gpio) + return bank; + + for (i = 0; i < ARRAY_SIZE(sun55iw3_vccio_banks); i++) { + if (sun55iw3_vccio_banks[i] == bank) + return 16; + } + return bank; +} + +void sun55iw3_pinctrl_fix_over_voltage(bool is_cpus_gpio) +{ + u32 mod_val, mod_sel, val, bank, i, vccio_sel_bank, vccio_val_bank, reg; + unsigned long flags; + int cur_uV, mod_uV, banks; + void __iomem *membase; + const u32 *bank_base; + u32 power_mode_sel_reg, power_mode_val_reg; + static u32 power_mon_print_once, r_power_mon_print_once; + + if (is_cpus_gpio) { + membase = ioremap(0x7022000, 0x800); + banks = ARRAY_SIZE(sun55iw3_r_bank_base); + bank_base = sun55iw3_r_bank_base; + + power_mode_sel_reg = 0x340; + power_mode_val_reg = 0x348; + } else { + membase = ioremap(0x2000000, 0x800); + banks = ARRAY_SIZE(sun55iw3_bank_base); + bank_base = sun55iw3_bank_base; + + power_mode_sel_reg = 0x380; + power_mode_val_reg = 0x388; + } + + + mod_val = readl(membase + power_mode_val_reg); + mod_sel = readl(membase + power_mode_sel_reg); + + for (i = 0; i < banks; i++) { + bank = bank_base[i]; + + /* Skip PF */ + if (i == 4) + continue; + + vccio_sel_bank = sun55iw3_vccio_sel_map(is_cpus_gpio, bank); + vccio_val_bank = sun55iw3_vccio_val_map(is_cpus_gpio, bank); + + mod_uV = mod_sel & BIT(vccio_sel_bank) ? 3300000 : 1800000; + + cur_uV = mod_val & BIT(vccio_val_bank) ? 1800000 : 3300000; + + if (is_cpus_gpio) + sunxi_debug(NULL, "bank[%c] power_val=%d, power_sel=%d\n", 'L' + bank, cur_uV, mod_uV); + else + sunxi_debug(NULL, "bank[%c] power_val=%d, power_sel=%d\n", 'A' + bank, cur_uV, mod_uV); + + if (cur_uV > mod_uV) { + if (is_cpus_gpio) + sunxi_warn(NULL, "bank[%c] over voltage, we will correct it\n", 'L' + bank); + else + sunxi_warn(NULL, "bank[%c] over voltage, we will correct it\n", 'A' + bank); + /* We always set power sel 3.3v */ + val = 1; + /* Set withstand voltage value */ + spin_lock_irqsave(&sun55iw3_pinctrl_lock, flags); + reg = readl(membase + power_mode_sel_reg); + reg &= ~BIT(vccio_sel_bank); + writel(reg | (val << vccio_sel_bank), membase + power_mode_sel_reg); + spin_unlock_irqrestore(&sun55iw3_pinctrl_lock, flags); + } else if (cur_uV < mod_uV) { + /* We print power mode warning once for every bank */ + if (is_cpus_gpio) { + if (!(r_power_mon_print_once & BIT(bank))) { + sunxi_warn(NULL, "bank[%c] power mode not correct, power_val=%d, power_sel=%d\n", + 'L' + bank, cur_uV, mod_uV); + r_power_mon_print_once |= BIT(bank); + } + } else { + if (!(power_mon_print_once & BIT(bank))) { + sunxi_warn(NULL, "bank[%c] power mode not correct, power_val=%d, power_sel=%d\n", + 'A' + bank, cur_uV, mod_uV); + power_mon_print_once |= BIT(bank); + } + } + } else { + /* Do nothing */ + } + } + + iounmap(membase); +} +EXPORT_SYMBOL_GPL(sun55iw3_pinctrl_fix_over_voltage); +#endif + static inline u32 sunxi_pintctrl_vccio_ctrl_map(struct sunxi_pinctrl *pctl, u32 bank) { enum sunxi_pinctrl_hw_type hw_type = pctl->desc->hw_type; @@ -696,18 +862,22 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl, unsigned pin, struct regulator *supply) { - unsigned short bank = pin / PINS_PER_BANK; - unsigned long flags; - u32 val, reg; + unsigned short bank; + unsigned long flags, g_flags; + u32 val, reg, vccio_ctrl_bank, vccio_sel_bank; int uV; enum sunxi_pinctrl_hw_type hw_type = pctl->desc->hw_type; bool power_mode_detect = sunxi_pinctrl_hw_info[hw_type].power_mode_detect; - u32 vccio_sel_bank = sunxi_pintctrl_vccio_sel_map(pctl, bank); - u32 vccio_ctrl_bank = sunxi_pintctrl_vccio_ctrl_map(pctl, bank); u32 power_mode_sel_reg = sunxi_pinctrl_hw_info[hw_type].power_mode_sel_reg; u32 power_mode_ctrl_reg = sunxi_pinctrl_hw_info[hw_type].power_mode_ctrl_reg; bool power_mode_reverse = sunxi_pinctrl_hw_info[hw_type].power_mode_reverse; + pin -= pctl->desc->pin_base; + bank = pin / PINS_PER_BANK; + + vccio_sel_bank = sunxi_pintctrl_vccio_sel_map(pctl, bank); + vccio_ctrl_bank = sunxi_pintctrl_vccio_ctrl_map(pctl, bank); + if (!pctl->desc->io_bias_cfg_variant) return 0; @@ -783,11 +953,14 @@ static int sunxi_pinctrl_set_io_bias_cfg(struct sunxi_pinctrl *pctl, val = uV <= 1800000 ? 1 : 0; /* Set withstand voltage value */ + spin_lock_irqsave(&sun55iw3_pinctrl_lock, g_flags); raw_spin_lock_irqsave(&pctl->lock, flags); reg = readl(pctl->membase + power_mode_sel_reg); reg &= ~BIT(vccio_sel_bank); writel(reg | val << vccio_sel_bank, pctl->membase + power_mode_sel_reg); + raw_spin_unlock_irqrestore(&pctl->lock, flags); + spin_unlock_irqrestore(&sun55iw3_pinctrl_lock, g_flags); sunxi_debug(NULL, "!pf-withstand: bank[%d-%d]=%duV set modesel[0x%x=0x%x]\n", bank, vccio_sel_bank, uV, power_mode_sel_reg, @@ -1007,7 +1180,7 @@ static void sunxi_power_switch_pf(struct sunxi_pinctrl *pctl, unsigned pin, u32 { u32 val, reg; u32 current_mV; - unsigned long flags; + unsigned long flags, g_flags; unsigned short bank = pin / PINS_PER_BANK; enum sunxi_pinctrl_hw_type hw_type = pctl->desc->hw_type; void __iomem *pow_val_addr = pctl->membase + sunxi_pinctrl_hw_info[hw_type].power_mode_val_reg; @@ -1027,6 +1200,7 @@ static void sunxi_power_switch_pf(struct sunxi_pinctrl *pctl, unsigned pin, u32 else val = 0; + spin_lock_irqsave(&sun55iw3_pinctrl_lock, g_flags); raw_spin_lock_irqsave(&pctl->lock, flags); /* 1.Set withstand voltage value */ reg = readl(pctl->membase + power_mode_sel_reg); @@ -1046,6 +1220,7 @@ static void sunxi_power_switch_pf(struct sunxi_pinctrl *pctl, unsigned pin, u32 val = 1; writel(val, pctl->membase + pio_pow_ctrl_reg); raw_spin_unlock_irqrestore(&pctl->lock, flags); + spin_unlock_irqrestore(&sun55iw3_pinctrl_lock, g_flags); /* Wait for voltage increasing. Double check! */ WARN_ON(readl_relaxed_poll_timeout(pow_val_addr, reg, !(reg & BIT(bank)), 100, 10000)); @@ -1071,6 +1246,7 @@ static void sunxi_power_switch_pf(struct sunxi_pinctrl *pctl, unsigned pin, u32 sunxi_debug(NULL, "pf-switch-decrease: 1.Wait for voltage decrease done[0x%x=0x%x]\n", power_mode_val_reg, readl(pctl->membase + power_mode_val_reg)); + spin_lock_irqsave(&sun55iw3_pinctrl_lock, g_flags); raw_spin_lock_irqsave(&pctl->lock, flags); if (power_mode_reverse) val = 0; @@ -1090,6 +1266,7 @@ static void sunxi_power_switch_pf(struct sunxi_pinctrl *pctl, unsigned pin, u32 reg &= ~BIT(bank); writel(reg | val << bank, pctl->membase + power_mode_ctrl_reg); raw_spin_unlock_irqrestore(&pctl->lock, flags); + spin_unlock_irqrestore(&sun55iw3_pinctrl_lock, g_flags); sunxi_debug(NULL, "pf-switch-decrease: 3.Disable self-adaption[0x%x=0x%x]\n", power_mode_ctrl_reg, readl(pctl->membase + power_mode_ctrl_reg)); @@ -2347,5 +2524,5 @@ int sunxi_bsp_pinctrl_init_with_variant(struct platform_device *pdev, } EXPORT_SYMBOL_GPL(sunxi_bsp_pinctrl_init_with_variant); MODULE_LICENSE("GPL"); -MODULE_VERSION("1.2.6"); +MODULE_VERSION("1.2.7"); MODULE_AUTHOR("lvda@allwinnertech.com"); diff --git a/bsp/drivers/pinctrl/pinctrl-sunxi.h b/bsp/drivers/pinctrl/pinctrl-sunxi.h index 65df8bf671..039a22cf12 100644 --- a/bsp/drivers/pinctrl/pinctrl-sunxi.h +++ b/bsp/drivers/pinctrl/pinctrl-sunxi.h @@ -132,6 +132,7 @@ enum sunxi_pinctrl_hw_type { SUNXI_PCTL_HW_TYPE_3, /* Newer chips: sun55iw3 */ SUNXI_PCTL_HW_TYPE_4, /* Newer chips: sun60iw2 */ SUNXI_PCTL_HW_TYPE_5, /* Support self-adaption */ + SUNXI_PCTL_HW_TYPE_6, /* chips: sun55iw3-prcm */ /* Add new types here ... */ SUNXI_PCTL_HW_TYPE_CNT, }; diff --git a/bsp/drivers/power/Kconfig b/bsp/drivers/power/Kconfig index 0df600ad61..66846a142e 100644 --- a/bsp/drivers/power/Kconfig +++ b/bsp/drivers/power/Kconfig @@ -91,6 +91,17 @@ config AW_REGULATOR_PMU_EXT This driver provides support for the voltage regulators on the PMU_EXT PMIC. +if AW_REGULATOR_PMU_EXT + +config AW_AXP1530_WORKAROUND_DVM + bool "AXP1530_EXT DVM" + default n + help + Say Y here if you want to enable axp1530 DVM function + +endif + + endif config AW_REGULATOR_PWM diff --git a/bsp/drivers/power/regulator/axp2101-regulator.c b/bsp/drivers/power/regulator/axp2101-regulator.c index 06eb47f464..a8408c9cbb 100644 --- a/bsp/drivers/power/regulator/axp2101-regulator.c +++ b/bsp/drivers/power/regulator/axp2101-regulator.c @@ -13,7 +13,6 @@ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. */ - #include #include #include @@ -27,6 +26,10 @@ #include #include +#define CPUX_GPIO 0 +#define CPUS_GPIO 1 +extern void sun55iw3_pinctrl_fix_over_voltage(bool is_cpus_gpio); + #define AXP20X_IO_ENABLED 0x03 #define AXP20X_IO_DISABLED 0x07 @@ -160,6 +163,14 @@ struct regulator_delay { u32 final; }; +#define MAX_NAME_LEN (20) +struct axp_reg_data { + struct regulator_delay rdev_delay; + struct regulator *virtual_consumer; + char consumer_name[MAX_NAME_LEN]; + struct notifier_block nb; +}; + static int regulator_is_enabled_regmap_axp2202_c_drivevbus(struct regulator_dev *rdev) { unsigned int val[2]; @@ -230,7 +241,8 @@ static int regulator_disable_regmap_axp2202_rbfet(struct regulator_dev *rdev) static int axp2101_set_voltage_time_sel(struct regulator_dev *rdev, unsigned int old_selector, unsigned int new_selector) { - struct regulator_delay *delay = (struct regulator_delay *)rdev->reg_data; + struct axp_reg_data *rdev_data = (struct axp_reg_data *)rdev_get_drvdata(rdev); + struct regulator_delay *delay = &rdev_data->rdev_delay; return abs(new_selector - old_selector) * delay->step + delay->final; }; @@ -1370,6 +1382,40 @@ static bool axp20x_is_polyphase_slave(struct axp20x_dev *axp20x, int id) return false; } +#if IS_ENABLED(CONFIG_ARCH_SUN55IW3) +void sunxi_pinctrl_fix_over_voltage(void) +{ + sun55iw3_pinctrl_fix_over_voltage(CPUX_GPIO); + sun55iw3_pinctrl_fix_over_voltage(CPUS_GPIO); +} + +static int sunxi_iodomain_notify(struct notifier_block *nb, + unsigned long event, + void *data) +{ + struct axp_reg_data *rdev_data = + container_of(nb, struct axp_reg_data, nb); + int uV; + + if (event & (REGULATOR_EVENT_VOLTAGE_CHANGE | + REGULATOR_EVENT_ABORT_VOLTAGE_CHANGE)) { + uV = (unsigned long)data; + /* Overvoltage detection is only required when the IO voltage changes */ + if (uV >= 1800000) { + mdelay(1); + pr_debug("[regulator]: %s set_voltage uV: %d\n", rdev_data->consumer_name, uV); + sunxi_pinctrl_fix_over_voltage(); + } + } else if (event & REGULATOR_EVENT_ENABLE) { + mdelay(1); + pr_debug("[regulator]: %s enable \n", rdev_data->consumer_name); + sunxi_pinctrl_fix_over_voltage(); + } + + return NOTIFY_OK; +} +#endif + static int axp2101_regulator_probe(struct platform_device *pdev) { struct regulator_dev *rdev; @@ -1387,7 +1433,8 @@ static int axp2101_regulator_probe(struct platform_device *pdev) const char *dcdc5_name = axp22x_regulators[AXP22X_DCDC5].name; bool drivevbus = false; u32 dval; - struct regulator_delay *rdev_delay; + struct axp_reg_data *rdev_data; + __maybe_unused const char *axp_reg_name; switch (axp20x->variant) { case AXP152_ID: @@ -1510,24 +1557,43 @@ static int axp2101_regulator_probe(struct platform_device *pdev) return PTR_ERR(rdev); } - rdev_delay = devm_kzalloc(&pdev->dev, sizeof(*rdev_delay), GFP_KERNEL); - if (!rdev_delay) { - PMIC_DEV_ERR(&pdev->dev, "rdev_delay kzalloc error %s\n", regulators[i].name); + rdev_data = devm_kzalloc(&pdev->dev, sizeof(*rdev_data), GFP_KERNEL); + if (!rdev_data) { + PMIC_DEV_ERR(&pdev->dev, "rdev_data kzalloc error %s\n", regulators[i].name); return -ENOMEM; } if (!of_property_read_u32(rdev->dev.of_node, "regulator-step-delay-us", &dval)) - rdev_delay->step = dval; + rdev_data->rdev_delay.step = dval; else - rdev_delay->step = 0; + rdev_data->rdev_delay.step = 0; if (!of_property_read_u32(rdev->dev.of_node, "regulator-final-delay-us", &dval)) - rdev_delay->final = dval; + rdev_data->rdev_delay.final = dval; else - rdev_delay->final = 0; + rdev_data->rdev_delay.final = 0; + + rdev->reg_data = rdev_data; + +#if IS_ENABLED(CONFIG_ARCH_SUN55IW3) + of_property_read_string(rdev->dev.of_node, "regulator-name", &axp_reg_name); + snprintf(rdev_data->consumer_name, MAX_NAME_LEN, "%s", axp_reg_name); + rdev_data->virtual_consumer = regulator_get_optional(NULL, axp_reg_name); + if (IS_ERR(rdev_data->virtual_consumer)) { + PMIC_DEV_ERR(&pdev->dev, "Failed to get regulator %s\n", axp_reg_name); + return PTR_ERR(rdev_data->virtual_consumer); + } - rdev->reg_data = rdev_delay; + rdev_data->nb.notifier_call = sunxi_iodomain_notify; + + /* register regulator notifier */ + ret = regulator_register_notifier(rdev_data->virtual_consumer, &rdev_data->nb); + if (ret) { + PMIC_DEV_ERR(&pdev->dev, "regulator notifier request failed\n"); + return ret; + } +#endif ret = of_property_read_u32(rdev->dev.of_node, "x-powers,dcdc-workmode", @@ -1554,6 +1620,11 @@ static int axp2101_regulator_probe(struct platform_device *pdev) &dcdc5_name); } +#if IS_ENABLED(CONFIG_ARCH_SUN55IW3) + /* Actively initiate overpressure detection */ + sunxi_pinctrl_fix_over_voltage(); +#endif + if (drivevbus) { switch (axp20x->variant) { case AXP221_ID: @@ -1645,4 +1716,4 @@ MODULE_LICENSE("GPL v2"); MODULE_AUTHOR("Carlo Caione "); MODULE_DESCRIPTION("Regulator Driver for AXP20X PMIC"); MODULE_ALIAS("platform:axp20x-regulator"); -MODULE_VERSION("1.0.0"); +MODULE_VERSION("1.0.1"); diff --git a/bsp/drivers/power/regulator/pmu-ext-regulator.c b/bsp/drivers/power/regulator/pmu-ext-regulator.c index 31cc942110..f2d8471401 100644 --- a/bsp/drivers/power/regulator/pmu-ext-regulator.c +++ b/bsp/drivers/power/regulator/pmu-ext-regulator.c @@ -89,6 +89,46 @@ .ops = &pmu_ext_ops_range_step_delay, \ } +#define AXP1530_EXT_HW_DVM_REGULATOR_RANGE_STEP_DELAY(_family, _id, _match, _supply, _ranges, _n_voltages, \ + _vreg, _vmask, _ereg, _emask) \ + [_family##_##_id] = { \ + .name = (_match), \ + .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .id = _family##_##_id, \ + .n_voltages = (_n_voltages), \ + .owner = THIS_MODULE, \ + .vsel_reg = (_vreg), \ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .linear_ranges = (_ranges), \ + .n_linear_ranges = ARRAY_SIZE(_ranges), \ + .ops = &axp1530_ext_hw_dvm_ops_range_step_delay, \ + } + +#define AXP1530_EXT_SW_DVM_REGULATOR_RANGE_STEP_DELAY(_family, _id, _match, _supply, _ranges, _n_voltages, \ + _vreg, _vmask, _ereg, _emask) \ + [_family##_##_id] = { \ + .name = (_match), \ + .supply_name = (_supply), \ + .of_match = of_match_ptr(_match), \ + .regulators_node = of_match_ptr("regulators"), \ + .type = REGULATOR_VOLTAGE, \ + .id = _family##_##_id, \ + .n_voltages = (_n_voltages), \ + .owner = THIS_MODULE, \ + .vsel_reg = (_vreg), \ + .vsel_mask = (_vmask), \ + .enable_reg = (_ereg), \ + .enable_mask = (_emask), \ + .linear_ranges = (_ranges), \ + .n_linear_ranges = ARRAY_SIZE(_ranges), \ + .ops = &axp1530_ext_sw_dvm_ops_range_step_delay, \ + } + struct regulator_delay { u32 step; u32 final; @@ -105,6 +145,178 @@ static int pmu_ext_set_voltage_time_sel(struct regulator_dev *rdev, return delay_time * 1000; }; +static int axp1530_ext_hw_dvm_set_voltage_time_sel_regmap(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct regulator_delay *delay = (struct regulator_delay *)rdev->reg_data; + int delay_time; + + if (abs(new_selector - old_selector)) + delay_time = (abs(new_selector - old_selector) * delay->step + delay->final + 999) / 1000; + else + delay_time = 0; + + mdelay(delay_time); + + return 0; +}; + +static int axp1530_ext_hw_dvm_set_voltage_sel_regmap(struct regulator_dev *rdev, unsigned sel) +{ + int ret; + int val; + sel <<= ffs(rdev->desc->vsel_mask) - 1; + + regmap_read(rdev->regmap, AXP1530_DCDC1_CONRTOL, &val); + val |= 0x80; + ret = regmap_write(rdev->regmap, AXP1530_DCDC2_CONRTOL, val); + + regmap_update_bits(rdev->regmap, 0x14, BIT(7), BIT(7)); + regmap_update_bits(rdev->regmap, 0x1d, BIT(0), 0); + regmap_update_bits(rdev->regmap, 0x22, BIT(1), 0); + + ret = regmap_update_bits(rdev->regmap, AXP1530_DCDC2_CONRTOL, + rdev->desc->vsel_mask, sel); + mdelay(1); + + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, sel); + udelay(500); + + regmap_update_bits(rdev->regmap, 0x22, BIT(1), BIT(1)); + + if (ret) + return ret; + + if (rdev->desc->apply_bit) + ret = regmap_update_bits(rdev->regmap, rdev->desc->apply_reg, + rdev->desc->apply_bit, + rdev->desc->apply_bit); + return ret; +} + +static int axp1530_ext_sw_dvm_set_voltage_time_sel(struct regulator_dev *rdev, + unsigned int old_selector, unsigned int new_selector) +{ + struct regulator_delay *delay = (struct regulator_delay *)rdev->reg_data; + int delay_time; + + if (abs(new_selector - old_selector)) + delay_time = (abs(new_selector - old_selector) * delay->step + delay->final); + else + delay_time = 0; + + return delay_time; +}; + +#define AXP1530_EXT_SW_DVM_STEP (2) +static int axp1530_ext_sw_dvm_set_voltage_sel_regmap + (struct regulator_dev *rdev, unsigned int new_selector) +{ + int ret; + int i, delay = 0; + int old_selector = -1; + int start_selector = 0; + unsigned int quot, rem; + const struct regulator_ops *ops = rdev->desc->ops; + + /* first step voltage 1.00v */ + start_selector = 50; + + old_selector = ops->get_voltage_sel(rdev); + if (old_selector < 0) + return old_selector; + + new_selector <<= ffs(rdev->desc->vsel_mask) - 1; + + if (new_selector <= old_selector) { + /* step down voltage */ + + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, new_selector); + if (ret) + return ret; + + delay = pmu_ext_set_voltage_time_sel(rdev, old_selector, new_selector); + mdelay(delay / 1000); + } else { + /* step up voltage */ + if ((old_selector < start_selector) && (start_selector <= new_selector)) { + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, + start_selector); + if (ret) + return ret; + delay = axp1530_ext_sw_dvm_set_voltage_time_sel(rdev, old_selector, + start_selector); + + if (delay >= 1000) { + mdelay(delay / 1000); + udelay(delay % 1000); + } else if (delay) { + udelay(delay); + } + old_selector = start_selector; + } else if (new_selector < start_selector) { + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, + new_selector); + if (ret) + return ret; + delay = axp1530_ext_sw_dvm_set_voltage_time_sel(rdev, old_selector, + new_selector); + if (delay >= 1000) { + mdelay(delay / 1000); + udelay(delay % 1000); + } else if (delay) { + udelay(delay); + } + old_selector = new_selector; + } + + quot = (new_selector - old_selector) / AXP1530_EXT_SW_DVM_STEP; + rem = (new_selector - old_selector) % AXP1530_EXT_SW_DVM_STEP; + for (i = 1; i <= quot; i++) { + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, + old_selector + AXP1530_EXT_SW_DVM_STEP * i); + if (ret) + return ret; + + /* delay for every dvm step */ + delay = axp1530_ext_sw_dvm_set_voltage_time_sel(rdev, + old_selector, + old_selector + AXP1530_EXT_SW_DVM_STEP); + if (delay >= 1000) { + mdelay(delay / 1000); + udelay(delay % 1000); + } else if (delay) { + udelay(delay); + } + } + + if (rem) { + ret = regmap_update_bits(rdev->regmap, rdev->desc->vsel_reg, + rdev->desc->vsel_mask, new_selector); + if (ret) + return ret; + + /* delay for remainder */ + delay = axp1530_ext_sw_dvm_set_voltage_time_sel(rdev, + old_selector, + old_selector + rem); + if (delay >= 1000) { + mdelay(delay / 1000); + udelay(delay % 1000); + } else if (delay) { + udelay(delay); + } + } + } + + return ret; +} + static struct regulator_ops pmu_ext_ops_step_delay = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, @@ -115,7 +327,7 @@ static struct regulator_ops pmu_ext_ops_step_delay = { .set_voltage_time_sel = pmu_ext_set_voltage_time_sel, }; -static struct regulator_ops pmu_ext_ops_range_step_delay = { +static struct regulator_ops __maybe_unused pmu_ext_ops_range_step_delay = { .set_voltage_sel = regulator_set_voltage_sel_regmap, .get_voltage_sel = regulator_get_voltage_sel_regmap, .list_voltage = regulator_list_voltage_linear_range, @@ -125,6 +337,25 @@ static struct regulator_ops pmu_ext_ops_range_step_delay = { .set_voltage_time_sel = pmu_ext_set_voltage_time_sel, }; +static struct regulator_ops __maybe_unused axp1530_ext_hw_dvm_ops_range_step_delay = { + .set_voltage_sel = axp1530_ext_hw_dvm_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, + .set_voltage_time_sel = axp1530_ext_hw_dvm_set_voltage_time_sel_regmap, +}; + +static struct regulator_ops __maybe_unused axp1530_ext_sw_dvm_ops_range_step_delay = { + .set_voltage_sel = axp1530_ext_sw_dvm_set_voltage_sel_regmap, + .get_voltage_sel = regulator_get_voltage_sel_regmap, + .list_voltage = regulator_list_voltage_linear_range, + .enable = regulator_enable_regmap, + .disable = regulator_disable_regmap, + .is_enabled = regulator_is_enabled_regmap, +}; + /* Operations permitted on DCDCx */ static struct regulator_ops pmu_ext_ops_range_vol_delay = { .is_enabled = regulator_is_enabled_regmap, @@ -152,12 +383,22 @@ static const struct linear_range axp1530_dcdc3_ranges[] = { }; static const struct regulator_desc axp1530_ext_regulators[] = { +#if !IS_ENABLED(CONFIG_AW_AXP1530_WORKAROUND_DVM) PMU_EXT_REGULATOR_RANGE_STEP_DELAY(AXP1530, DCDC1, "dcdc1", "vin1", axp1530_dcdc1_ranges, 0x6B, AXP1530_DCDC1_CONRTOL, 0x7f, AXP1530_OUTPUT_CONTROL, BIT(0)), PMU_EXT_REGULATOR_RANGE_STEP_DELAY(AXP1530, DCDC2, "dcdc2", "vin2", axp1530_dcdc2_ranges, 0x58, AXP1530_DCDC2_CONRTOL, 0x7f, AXP1530_OUTPUT_CONTROL, BIT(1)), PMU_EXT_REGULATOR_RANGE_STEP_DELAY(AXP1530, DCDC3, "dcdc3", "vin3", axp1530_dcdc3_ranges, 0x58, AXP1530_DCDC3_CONRTOL, 0x7f, AXP1530_OUTPUT_CONTROL, BIT(2)), +#else + AXP1530_EXT_HW_DVM_REGULATOR_RANGE_STEP_DELAY(AXP1530, DCDC1, "dcdc1", "vin1", axp1530_dcdc1_ranges, + 0x6B, AXP1530_DCDC1_CONRTOL, 0x7f, AXP1530_OUTPUT_CONTROL, BIT(0)), + AXP1530_EXT_HW_DVM_REGULATOR_RANGE_STEP_DELAY(AXP1530, DCDC2, "dcdc2", "vin2", axp1530_dcdc2_ranges, + 0x58, AXP1530_DCDC2_CONRTOL, 0x7f, AXP1530_OUTPUT_CONTROL, BIT(1)), + AXP1530_EXT_SW_DVM_REGULATOR_RANGE_STEP_DELAY(AXP1530, DCDC3, "dcdc3", "vin3", axp1530_dcdc3_ranges, + 0x58, AXP1530_DCDC3_CONRTOL, 0x7f, AXP1530_OUTPUT_CONTROL, BIT(2)), +#endif + PMU_EXT_REGULATOR_STEP_DELAY(AXP1530, LDO1, "ldo1", "ldo1in", 500, 3500, 100, AXP1530_ALDO1_CONRTOL, 0x1f, AXP1530_OUTPUT_CONTROL, BIT(3)), PMU_EXT_REGULATOR_STEP_DELAY(AXP1530, LDO2, "ldo2", "ldo2in", 500, 3500, 100, diff --git a/bsp/drivers/power/supply/axp2202_usb_power.c b/bsp/drivers/power/supply/axp2202_usb_power.c index 1ea4c57136..26a34c5d3c 100644 --- a/bsp/drivers/power/supply/axp2202_usb_power.c +++ b/bsp/drivers/power/supply/axp2202_usb_power.c @@ -611,6 +611,10 @@ static void axp2202_usb_det_monitor(struct work_struct *work) cancel_delayed_work_sync(&usb_power->usb_chg_state); schedule_delayed_work(&usb_power->usb_chg_state, msecs_to_jiffies(5 * 1000)); } + } else { + regmap_update_bits(usb_power->regmap, AXP2202_CC_MODE_CTRL, GENMASK(1, 0), 0); + mdelay(50); + regmap_update_bits(usb_power->regmap, AXP2202_CC_MODE_CTRL, GENMASK(1, 0), 0x3); } } diff --git a/bsp/drivers/sound/platform/Kconfig b/bsp/drivers/sound/platform/Kconfig index fb323497dc..901c9aa44f 100644 --- a/bsp/drivers/sound/platform/Kconfig +++ b/bsp/drivers/sound/platform/Kconfig @@ -150,7 +150,12 @@ config SND_SOC_SUNXI_CODEC_EDP depends on ARCH_SUN55IW3 help Select Y or M to support edp audio in Allwinner SoCs. - +#AVAUDIO +config SND_SOC_SUNXI_CODEC_AV + tristate "Allwinner AVAUDIO support" + depends on ARCH_SUN55IW3 + help + Select Y or M to support av audio in Allwinner SoCs. endif # ahub diff --git a/bsp/drivers/sound/platform/Makefile b/bsp/drivers/sound/platform/Makefile index 8d98910bcd..0e257af9cf 100644 --- a/bsp/drivers/sound/platform/Makefile +++ b/bsp/drivers/sound/platform/Makefile @@ -60,6 +60,10 @@ obj-$(CONFIG_SND_SOC_SUNXI_CODEC_HDMI) += snd_soc_sunxi_codec_hdmi.o snd_soc_sunxi_codec_edp-objs += snd_sunxi_codec_edp.o obj-$(CONFIG_SND_SOC_SUNXI_CODEC_EDP) += snd_soc_sunxi_codec_edp.o +# codec -> av codec +snd_soc_sunxi_codec_av-objs += snd_sunxi_codec_av.o +obj-$(CONFIG_SND_SOC_SUNXI_CODEC_AV) += snd_soc_sunxi_codec_av.o + # platform -> analog audio snd_soc_sunxi_aaudio-objs += snd_sunxi_aaudio.o obj-$(CONFIG_SND_SOC_SUNXI_AAUDIO) += snd_soc_sunxi_aaudio.o diff --git a/bsp/drivers/sound/platform/snd_sunxi_codec_av.c b/bsp/drivers/sound/platform/snd_sunxi_codec_av.c new file mode 100644 index 0000000000..cef5d27a56 --- /dev/null +++ b/bsp/drivers/sound/platform/snd_sunxi_codec_av.c @@ -0,0 +1,273 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* Copyright(c) 2020 - 2024 Allwinner Technology Co.,Ltd. All rights reserved. */ +/* + * Allwinner's ALSA SoC Audio driver + * + * Copyright (c) 2023, zhouxijing + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of + * the License, or (at your option) any later version. + */ + +#define SUNXI_MODNAME "sound-codec-av" +#include "snd_sunxi_log.h" +#include +#include +#include +#include + +#include "snd_sunxi_common.h" + +#define DRV_NAME "sunxi-snd-codec-av" + +struct sunxi_codec { + struct platform_device *pdev; + + struct hdmi_codec_daifmt daifmt; + struct hdmi_codec_params params; + struct hdmi_codec_pdata *pdata; +}; + +static int sunxi_codec_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt) +{ + struct snd_soc_component *component = dai->component; + struct sunxi_codec *codec = snd_soc_component_get_drvdata(component); + struct hdmi_codec_daifmt *daifmt = &codec->daifmt; + + SND_LOG_DEBUG("\n"); + + /* get dai mode */ + switch (fmt & SND_SOC_DAIFMT_FORMAT_MASK) { + case SND_SOC_DAIFMT_I2S: + daifmt->fmt = HDMI_I2S; + break; + case SND_SOC_DAIFMT_RIGHT_J: + daifmt->fmt = HDMI_RIGHT_J; + break; + case SND_SOC_DAIFMT_LEFT_J: + daifmt->fmt = HDMI_LEFT_J; + break; + case SND_SOC_DAIFMT_DSP_A: + daifmt->fmt = HDMI_DSP_A; + break; + case SND_SOC_DAIFMT_DSP_B: + daifmt->fmt = HDMI_DSP_B; + break; + default: + SND_LOG_ERR("hdmi_codec_daifmt fmt set fail\n"); + return -EINVAL; + } + + return 0; +} + +static int sunxi_codec_dai_hw_params(struct snd_pcm_substream *substream, + struct snd_pcm_hw_params *params, + struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct sunxi_codec *codec = snd_soc_component_get_drvdata(component); + struct hdmi_codec_params *codec_params = &codec->params; + struct hdmi_codec_daifmt *daifmt = &codec->daifmt; + struct hdmi_codec_pdata *pdata = codec->pdata; + int ret; + + SND_LOG_DEBUG("\n"); + + switch (params_format(params)) { + case SNDRV_PCM_FORMAT_S16_LE: + codec_params->sample_width = 16; + break; + case SNDRV_PCM_FORMAT_S20_3LE: + case SNDRV_PCM_FORMAT_S24_3LE: + codec_params->sample_width = 20; + break; + case SNDRV_PCM_FORMAT_S24_LE: + case SNDRV_PCM_FORMAT_S32_LE: + codec_params->sample_width = 24; + break; + default: + return -EINVAL; + } + codec_params->channels = params_channels(params); + codec_params->sample_rate = params_rate(params); + + ret = pdata->ops->hw_params(component->dev->parent, NULL, daifmt, codec_params); + if (ret < 0) { + SND_LOG_ERR("hdmi_codec_pdata hw params fail\n"); + return ret; + } + + return 0; +} + +static int sunxi_codec_dai_startup(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct sunxi_codec *codec = snd_soc_component_get_drvdata(component); + struct hdmi_codec_pdata *pdata = codec->pdata; + int ret; + + SND_LOG_DEBUG("\n"); + + ret = pdata->ops->audio_startup(component->dev->parent, NULL); + if (ret < 0) { + SND_LOG_ERR("hdmi_codec_pdata startup fail\n"); + return ret; + } + + return 0; +} + +static int sunxi_codec_dai_mute_stream(struct snd_soc_dai *dai, int mute, int stream) +{ + struct snd_soc_component *component = dai->component; + struct sunxi_codec *codec = snd_soc_component_get_drvdata(component); + struct hdmi_codec_pdata *pdata = codec->pdata; + int ret; + + SND_LOG_DEBUG("\n"); + + ret = pdata->ops->mute_stream(component->dev->parent, NULL, mute, stream); + if (ret < 0) { + SND_LOG_ERR("hdmi_codec_pdata mute stream fail\n"); + return ret; + } + + return 0; +} + +static void sunxi_codec_dai_shutdown(struct snd_pcm_substream *substream, struct snd_soc_dai *dai) +{ + struct snd_soc_component *component = dai->component; + struct sunxi_codec *codec = snd_soc_component_get_drvdata(component); + struct hdmi_codec_pdata *pdata = codec->pdata; + + SND_LOG_DEBUG("\n"); + + pdata->ops->audio_shutdown(component->dev->parent, NULL); +} + +static const struct snd_soc_dai_ops sunxi_codec_dai_ops = { + .set_fmt = sunxi_codec_dai_set_fmt, + .hw_params = sunxi_codec_dai_hw_params, + .startup = sunxi_codec_dai_startup, + .mute_stream = sunxi_codec_dai_mute_stream, + .shutdown = sunxi_codec_dai_shutdown, +}; + +static struct snd_soc_dai_driver sunxi_codec_dai = { + .name = DRV_NAME, + .playback = { + .stream_name = "Playback", + .channels_min = 1, + .channels_max = 8, + .rates = SNDRV_PCM_RATE_8000_192000 + | SNDRV_PCM_RATE_KNOT, + .formats = SNDRV_PCM_FMTBIT_S16_LE + | SNDRV_PCM_FMTBIT_S20_LE + | SNDRV_PCM_FMTBIT_S24_LE + | SNDRV_PCM_FMTBIT_S24_3LE + | SNDRV_PCM_FMTBIT_S32_LE, + }, + .ops = &sunxi_codec_dai_ops, +}; + +static struct snd_soc_component_driver sunxi_codec_component_dev = { + .name = DRV_NAME, +}; + +static int sunxi_codec_dev_probe(struct platform_device *pdev) +{ + struct hdmi_codec_pdata *pdata = pdev->dev.platform_data; + struct device *dev = &pdev->dev; + struct sunxi_codec *codec; + int ret; + const char *devname = dev_name(dev); + + SND_LOG_DEBUG("device name:%s\n", devname); + + if (!pdata) { + SND_LOG_ERR("No hdmi codec pdata\n"); + return -EINVAL; + } + + if (!pdata->ops || !pdata->ops->hw_params || !pdata->ops->audio_startup || + !pdata->ops->audio_shutdown || !pdata->ops->mute_stream) { + SND_LOG_ERR("ops incomplete\n"); + return -EINVAL; + } + + /* sunxi codec info */ + codec = devm_kzalloc(dev, sizeof(struct sunxi_codec), GFP_KERNEL); + if (!codec) { + SND_LOG_ERR("can't allocate sunxi codec av memory\n"); + return -ENOMEM; + } + codec->pdev = pdev; + codec->pdata = pdata; + dev_set_drvdata(dev, codec); + + /* alsa component register */ + ret = snd_soc_register_component(dev, &sunxi_codec_component_dev, &sunxi_codec_dai, 1); + if (ret) { + SND_LOG_ERR("codec-av component register failed\n"); + return -EINVAL; + } + + SND_LOG_DEBUG("register codec-av success\n"); + + return 0; +} + +static int sunxi_codec_dev_remove(struct platform_device *pdev) +{ + struct device *dev = &pdev->dev; + struct sunxi_codec *codec = dev_get_drvdata(dev); + + SND_LOG_DEBUG("\n"); + + snd_soc_unregister_component(dev); + + devm_kfree(dev, codec); + + SND_LOG_DEBUG("unregister codec-hdmi success\n"); + + return 0; +} + +static struct platform_driver sunxi_codec_driver = { + .driver = { + .name = DRV_NAME, + }, + .probe = sunxi_codec_dev_probe, + .remove = sunxi_codec_dev_remove, +}; + +int __init sunxi_av_codec_dev_init(void) +{ + int ret; + + ret = platform_driver_register(&sunxi_codec_driver); + if (ret != 0) { + SND_LOG_ERR("platform driver register failed\n"); + return -EINVAL; + } + + return ret; +} + +void __exit sunxi_av_codec_dev_exit(void) +{ + platform_driver_unregister(&sunxi_codec_driver); +} + +late_initcall(sunxi_av_codec_dev_init); +module_exit(sunxi_av_codec_dev_exit); + +MODULE_AUTHOR("zhouxijing@allwinnertech.com"); +MODULE_LICENSE("GPL"); +MODULE_VERSION("1.0.0"); +MODULE_DESCRIPTION("sunxi soundcard codec of av"); diff --git a/bsp/drivers/sound/platform/snd_sunxi_mach.c b/bsp/drivers/sound/platform/snd_sunxi_mach.c index 9b05615012..d2a3f52416 100644 --- a/bsp/drivers/sound/platform/snd_sunxi_mach.c +++ b/bsp/drivers/sound/platform/snd_sunxi_mach.c @@ -363,14 +363,17 @@ static int simple_dai_link_of(struct device_node *node, struct asoc_simple_priv if (ret < 0) { if (ret == -EPROBE_DEFER) goto dai_link_of_err; - dai_link->codecs = devm_kcalloc(dev, 1, sizeof(*(dai_link->codecs)), - GFP_KERNEL); - dai_link->num_codecs = 1; - dai_link->codecs->name = "snd-soc-dummy"; - dai_link->codecs->dai_name = "snd-soc-dummy-dai"; - /* dai_link->codecs->name = "sunxi-dummy-codec"; */ - /* dai_link->codecs->dai_name = "sunxi-dummy-codec-dai"; */ - SND_LOG_DEBUG("use dummy codec for simple card.\n"); + ret = asoc_simple_parse_dlc_name(dev, codec, prefix, dai_link); + if (ret < 0) { + dai_link->codecs = devm_kcalloc(dev, 1, sizeof(*(dai_link->codecs)), + GFP_KERNEL); + dai_link->num_codecs = 1; + dai_link->codecs->name = "snd-soc-dummy"; + dai_link->codecs->dai_name = "snd-soc-dummy-dai"; + /* dai_link->codecs->name = "sunxi-dummy-codec"; */ + /* dai_link->codecs->dai_name = "sunxi-dummy-codec-dai"; */ + SND_LOG_DEBUG("use dummy codec for simple card.\n"); + } } ret = asoc_simple_parse_platform(plat, dai_link, DAI, CELL); if (ret < 0) diff --git a/bsp/drivers/sound/platform/snd_sunxi_mach_utils.c b/bsp/drivers/sound/platform/snd_sunxi_mach_utils.c index 94bbc38944..66aca4b6c0 100644 --- a/bsp/drivers/sound/platform/snd_sunxi_mach_utils.c +++ b/bsp/drivers/sound/platform/snd_sunxi_mach_utils.c @@ -424,6 +424,45 @@ int asoc_simple_parse_tdm_slot(struct device_node *node, char *prefix, return 0; } +int asoc_simple_parse_dlc_name(struct device *dev, struct device_node *node, + char *prefix, struct snd_soc_dai_link *dai_link) +{ + int ret; + int num; + unsigned int i; + char dlc_prop[128], dai_prop[128]; + struct snd_soc_dai_link_component *component; + + if (!prefix) + prefix = ""; + + snprintf(dlc_prop, sizeof(dlc_prop), "%sdlc-names", prefix); + num = of_property_count_strings(node, dlc_prop); + if (num < 0) + return -EINVAL; + + component = devm_kcalloc(dev, num, sizeof(*component), GFP_KERNEL); + if (!component) + return -ENOMEM; + + for (i = 0; i < num; i++) { + ret = of_property_read_string_index(node, dlc_prop, i, &component[i].name); + if (ret < 0) + return ret; + + snprintf(dai_prop, sizeof(dai_prop), "%sdlc%d-dai-name", prefix, i); + ret = of_property_read_string(node, dai_prop, &component[i].dai_name); + if (ret < 0) + SND_LOG_WARN("confirm if this component without dai:%s\n", + component[i].name); + } + + dai_link->num_codecs = num; + dai_link->codecs = component; + + return 0; +} + int asoc_simple_parse_tdm_clk(struct device_node *cpu, struct device_node *codec, char *prefix, diff --git a/bsp/drivers/sound/platform/snd_sunxi_mach_utils.h b/bsp/drivers/sound/platform/snd_sunxi_mach_utils.h index 73be2a9af6..0b77b20420 100644 --- a/bsp/drivers/sound/platform/snd_sunxi_mach_utils.h +++ b/bsp/drivers/sound/platform/snd_sunxi_mach_utils.h @@ -112,6 +112,8 @@ int asoc_simple_parse_daifmt(struct device_node *node, int asoc_simple_parse_tdm_slot(struct device_node *node, char *prefix, struct asoc_simple_dai *dais); +int asoc_simple_parse_dlc_name(struct device *dev, struct device_node *node, + char *prefix, struct snd_soc_dai_link *dai_link); int asoc_simple_parse_tdm_clk(struct device_node *cpu, struct device_node *codec, char *prefix, diff --git a/bsp/drivers/video/sunxi/disp2/disp/de/include.h b/bsp/drivers/video/sunxi/disp2/disp/de/include.h index 26bae46236..5bbe543d2e 100644 --- a/bsp/drivers/video/sunxi/disp2/disp/de/include.h +++ b/bsp/drivers/video/sunxi/disp2/disp/de/include.h @@ -65,7 +65,7 @@ #include #include -#include