Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH 3/3] arm64: kexec_file: add crash dump support
From: AKASHI Takahiro @ 2019-09-12  6:01 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list
  Cc: kexec, james.morse, linux-kernel, linux-arm-kernel,
	AKASHI Takahiro
In-Reply-To: <20190912060150.10818-1-takahiro.akashi@linaro.org>

Enabling crash dump (kdump) includes
* prepare contents of ELF header of a core dump file, /proc/vmcore,
  using crash_prepare_elf64_headers(), and
* add two device tree properties, "linux,usable-memory-range" and
  "linux,elfcorehdr", which represent respectively a memory range
  to be used by crash dump kernel and the header's location

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
Cc: Will Deacon <will.deacon@arm.com>
Reviewed-by: James Morse <james.morse@arm.com>
---
 arch/arm64/include/asm/kexec.h         |   4 +
 arch/arm64/kernel/kexec_image.c        |   4 -
 arch/arm64/kernel/machine_kexec_file.c | 105 ++++++++++++++++++++++++-
 3 files changed, 106 insertions(+), 7 deletions(-)

diff --git a/arch/arm64/include/asm/kexec.h b/arch/arm64/include/asm/kexec.h
index 12a561a54128..d24b527e8c00 100644
--- a/arch/arm64/include/asm/kexec.h
+++ b/arch/arm64/include/asm/kexec.h
@@ -96,6 +96,10 @@ static inline void crash_post_resume(void) {}
 struct kimage_arch {
 	void *dtb;
 	unsigned long dtb_mem;
+	/* Core ELF header buffer */
+	void *elf_headers;
+	unsigned long elf_headers_mem;
+	unsigned long elf_headers_sz;
 };
 
 extern const struct kexec_file_ops kexec_image_ops;
diff --git a/arch/arm64/kernel/kexec_image.c b/arch/arm64/kernel/kexec_image.c
index 2514fd6f12cb..60cedfa9529b 100644
--- a/arch/arm64/kernel/kexec_image.c
+++ b/arch/arm64/kernel/kexec_image.c
@@ -47,10 +47,6 @@ static void *image_load(struct kimage *image,
 	struct kexec_segment *kernel_segment;
 	int ret;
 
-	/* We don't support crash kernels yet. */
-	if (image->type == KEXEC_TYPE_CRASH)
-		return ERR_PTR(-EOPNOTSUPP);
-
 	/*
 	 * We require a kernel with an unambiguous Image header. Per
 	 * Documentation/arm64/booting.rst, this is the case when image_size
diff --git a/arch/arm64/kernel/machine_kexec_file.c b/arch/arm64/kernel/machine_kexec_file.c
index 58871333737a..f5276e27c12b 100644
--- a/arch/arm64/kernel/machine_kexec_file.c
+++ b/arch/arm64/kernel/machine_kexec_file.c
@@ -17,12 +17,15 @@
 #include <linux/memblock.h>
 #include <linux/of_fdt.h>
 #include <linux/random.h>
+#include <linux/slab.h>
 #include <linux/string.h>
 #include <linux/types.h>
 #include <linux/vmalloc.h>
 #include <asm/byteorder.h>
 
 /* relevant device tree properties */
+#define FDT_PROP_KEXEC_ELFHDR	"linux,elfcorehdr"
+#define FDT_PROP_MEM_RANGE	"linux,usable-memory-range"
 #define FDT_PROP_INITRD_START	"linux,initrd-start"
 #define FDT_PROP_INITRD_END	"linux,initrd-end"
 #define FDT_PROP_BOOTARGS	"bootargs"
@@ -38,6 +41,10 @@ int arch_kimage_file_post_load_cleanup(struct kimage *image)
 	vfree(image->arch.dtb);
 	image->arch.dtb = NULL;
 
+	vfree(image->arch.elf_headers);
+	image->arch.elf_headers = NULL;
+	image->arch.elf_headers_sz = 0;
+
 	return kexec_image_post_load_cleanup_default(image);
 }
 
@@ -53,6 +60,31 @@ static int setup_dtb(struct kimage *image,
 
 	off = ret;
 
+	ret = fdt_delprop(dtb, off, FDT_PROP_KEXEC_ELFHDR);
+	if (ret && ret != -FDT_ERR_NOTFOUND)
+		goto out;
+	ret = fdt_delprop(dtb, off, FDT_PROP_MEM_RANGE);
+	if (ret && ret != -FDT_ERR_NOTFOUND)
+		goto out;
+
+	if (image->type == KEXEC_TYPE_CRASH) {
+		/* add linux,elfcorehdr */
+		ret = fdt_appendprop_addrrange(dtb, 0, off,
+				FDT_PROP_KEXEC_ELFHDR,
+				image->arch.elf_headers_mem,
+				image->arch.elf_headers_sz);
+		if (ret)
+			return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
+
+		/* add linux,usable-memory-range */
+		ret = fdt_appendprop_addrrange(dtb, 0, off,
+				FDT_PROP_MEM_RANGE,
+				crashk_res.start,
+				crashk_res.end - crashk_res.start + 1);
+		if (ret)
+			return (ret == -FDT_ERR_NOSPACE ? -ENOMEM : -EINVAL);
+	}
+
 	/* add bootargs */
 	if (cmdline) {
 		ret = fdt_setprop_string(dtb, off, FDT_PROP_BOOTARGS, cmdline);
@@ -110,7 +142,8 @@ static int setup_dtb(struct kimage *image,
 }
 
 /*
- * More space needed so that we can add initrd, bootargs and kaslr-seed.
+ * More space needed so that we can add initrd, bootargs, kaslr-seed,
+ * userable-memory-range and elfcorehdr.
  */
 #define DTB_EXTRA_SPACE 0x1000
 
@@ -158,6 +191,43 @@ static int create_dtb(struct kimage *image,
 	}
 }
 
+static int prepare_elf_headers(void **addr, unsigned long *sz)
+{
+	struct crash_mem *cmem;
+	unsigned int nr_ranges;
+	int ret;
+	u64 i;
+	phys_addr_t start, end;
+
+	nr_ranges = 1; /* for exclusion of crashkernel region */
+	for_each_mem_range(i, &memblock.memory, NULL, NUMA_NO_NODE,
+					MEMBLOCK_NONE, &start, &end, NULL)
+		nr_ranges++;
+
+	cmem = kmalloc(sizeof(struct crash_mem) +
+			sizeof(struct crash_mem_range) * nr_ranges, GFP_KERNEL);
+	if (!cmem)
+		return -ENOMEM;
+
+	cmem->max_nr_ranges = nr_ranges;
+	cmem->nr_ranges = 0;
+	for_each_mem_range(i, &memblock.memory, NULL, NUMA_NO_NODE,
+					MEMBLOCK_NONE, &start, &end, NULL) {
+		cmem->ranges[cmem->nr_ranges].start = start;
+		cmem->ranges[cmem->nr_ranges].end = end - 1;
+		cmem->nr_ranges++;
+	}
+
+	/* Exclude crashkernel region */
+	ret = crash_exclude_mem_range(cmem, crashk_res.start, crashk_res.end);
+
+	if (!ret)
+		ret =  crash_prepare_elf64_headers(cmem, true, addr, sz);
+
+	kfree(cmem);
+	return ret;
+}
+
 int load_other_segments(struct kimage *image,
 			unsigned long kernel_load_addr,
 			unsigned long kernel_size,
@@ -165,14 +235,43 @@ int load_other_segments(struct kimage *image,
 			char *cmdline)
 {
 	struct kexec_buf kbuf;
-	void *dtb = NULL;
-	unsigned long initrd_load_addr = 0, dtb_len;
+	void *headers, *dtb = NULL;
+	unsigned long headers_sz, initrd_load_addr = 0, dtb_len;
 	int ret = 0;
 
 	kbuf.image = image;
 	/* not allocate anything below the kernel */
 	kbuf.buf_min = kernel_load_addr + kernel_size;
 
+	/* load elf core header */
+	if (image->type == KEXEC_TYPE_CRASH) {
+		ret = prepare_elf_headers(&headers, &headers_sz);
+		if (ret) {
+			pr_err("Preparing elf core header failed\n");
+			goto out_err;
+		}
+
+		kbuf.buffer = headers;
+		kbuf.bufsz = headers_sz;
+		kbuf.mem = 0;
+		kbuf.memsz = headers_sz;
+		kbuf.buf_align = SZ_64K; /* largest supported page size */
+		kbuf.buf_max = ULONG_MAX;
+		kbuf.top_down = true;
+
+		ret = kexec_add_buffer(&kbuf);
+		if (ret) {
+			vfree(headers);
+			goto out_err;
+		}
+		image->arch.elf_headers = headers;
+		image->arch.elf_headers_mem = kbuf.mem;
+		image->arch.elf_headers_sz = headers_sz;
+
+		pr_debug("Loaded elf core header at 0x%lx bufsz=0x%lx memsz=0x%lx\n",
+			 image->arch.elf_headers_mem, headers_sz, headers_sz);
+	}
+
 	/* load initrd */
 	if (initrd) {
 		kbuf.buffer = initrd;
-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 2/3] libfdt: include fdt_addresses.c
From: AKASHI Takahiro @ 2019-09-12  6:01 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list
  Cc: kexec, james.morse, linux-kernel, linux-arm-kernel,
	AKASHI Takahiro
In-Reply-To: <20190912060150.10818-1-takahiro.akashi@linaro.org>

In the implementation of kexec_file_loaded-based kdump for arm64,
fdt_appendprop_addrrange() will be needed.

So include fdt_addresses.c in making libfdt.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Frank Rowand <frowand.list@gmail.com>
---
 lib/Makefile        | 2 +-
 lib/fdt_addresses.c | 2 ++
 2 files changed, 3 insertions(+), 1 deletion(-)
 create mode 100644 lib/fdt_addresses.c

diff --git a/lib/Makefile b/lib/Makefile
index 29c02a924973..59f082727503 100644
--- a/lib/Makefile
+++ b/lib/Makefile
@@ -224,7 +224,7 @@ KASAN_SANITIZE_stackdepot.o := n
 KCOV_INSTRUMENT_stackdepot.o := n
 
 libfdt_files = fdt.o fdt_ro.o fdt_wip.o fdt_rw.o fdt_sw.o fdt_strerror.o \
-	       fdt_empty_tree.o
+	       fdt_empty_tree.o fdt_addresses.o
 $(foreach file, $(libfdt_files), \
 	$(eval CFLAGS_$(file) = -I $(srctree)/scripts/dtc/libfdt))
 lib-$(CONFIG_LIBFDT) += $(libfdt_files)
diff --git a/lib/fdt_addresses.c b/lib/fdt_addresses.c
new file mode 100644
index 000000000000..23610bcf390b
--- /dev/null
+++ b/lib/fdt_addresses.c
@@ -0,0 +1,2 @@
+#include <linux/libfdt_env.h>
+#include "../scripts/dtc/libfdt/fdt_addresses.c"
-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 1/3] libfdt: define UINT32_MAX in libfdt_env.h
From: AKASHI Takahiro @ 2019-09-12  6:01 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list
  Cc: kexec, james.morse, linux-kernel, linux-arm-kernel,
	AKASHI Takahiro
In-Reply-To: <20190912060150.10818-1-takahiro.akashi@linaro.org>

In the implementation of kexec_file_load-based kdump for arm64,
fdt_appendprop_addrrange() will be used, but fdt_addresses.c
will fail to compile due to missing UINT32_MAX.

So just define it in libfdt_env.h.

Signed-off-by: AKASHI Takahiro <takahiro.akashi@linaro.org>
Cc: Rob Herring <robh+dt@kernel.org>
Cc: Frank Rowand <frowand.list@gmail.com>
---
 include/linux/libfdt_env.h | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/include/linux/libfdt_env.h b/include/linux/libfdt_env.h
index edb0f0c30904..9ca00f11d9b1 100644
--- a/include/linux/libfdt_env.h
+++ b/include/linux/libfdt_env.h
@@ -3,6 +3,7 @@
 #define LIBFDT_ENV_H
 
 #include <linux/kernel.h>	/* For INT_MAX */
+#include <linux/limits.h>	/* For UINT32_MAX */
 #include <linux/string.h>
 
 #include <asm/byteorder.h>
@@ -11,6 +12,8 @@ typedef __be16 fdt16_t;
 typedef __be32 fdt32_t;
 typedef __be64 fdt64_t;
 
+#define UINT32_MAX U32_MAX
+
 #define fdt32_to_cpu(x) be32_to_cpu(x)
 #define cpu_to_fdt32(x) cpu_to_be32(x)
 #define fdt64_to_cpu(x) be64_to_cpu(x)
-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 0/3] arm64: kexec_file: add kdump
From: AKASHI Takahiro @ 2019-09-12  6:01 UTC (permalink / raw)
  To: catalin.marinas, will.deacon, robh+dt, frowand.list
  Cc: kexec, james.morse, linux-kernel, linux-arm-kernel,
	AKASHI Takahiro

This is the last piece of my kexec_file_load implementation for arm64.
It is now ready for being merged as some relevant patch to dtc/libfdt[1]
has finally been integrated in v5.3-rc1.
(Nothing changed since kexec_file v16[2] except adding Patch#1 and #2.)

Patch#1 and #2 are preliminary patches for libfdt component.
Patch#3 is to add kdump support.

[1] commit 9bb9c6a110ea ("scripts/dtc: Update to upstream version
    v1.5.0-23-g87963ee20693"), in particular
	7fcf8208b8a9 libfdt: add fdt_append_addrrange()
[2] http://lists.infradead.org/pipermail/linux-arm-kernel/2018-November/612641.html

AKASHI Takahiro (3):
  libfdt: define UINT32_MAX in libfdt_env.h
  libfdt: include fdt_addresses.c
  arm64: kexec_file: add crash dump support

 arch/arm64/include/asm/kexec.h         |   4 +
 arch/arm64/kernel/kexec_image.c        |   4 -
 arch/arm64/kernel/machine_kexec_file.c | 105 ++++++++++++++++++++++++-
 include/linux/libfdt_env.h             |   3 +
 lib/Makefile                           |   2 +-
 lib/fdt_addresses.c                    |   2 +
 6 files changed, 112 insertions(+), 8 deletions(-)
 create mode 100644 lib/fdt_addresses.c

-- 
2.21.0


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* RE: [PATCH v1 3/3] scsi: ufs-mediatek: enable auto suspend capability
From: Stanley Chu @ 2019-09-12  5:39 UTC (permalink / raw)
  To: Avri Altman
  Cc: sthumma@codeaurora.org, linux-scsi@vger.kernel.org,
	martin.petersen@oracle.com, marc.w.gonzalez@free.fr,
	vivek.gautam@codeaurora.org, andy.teng@mediatek.com,
	jejb@linux.ibm.com, chun-hung.wu@mediatek.com,
	kuohong.wang@mediatek.com, evgreen@chromium.org,
	subhashj@codeaurora.org, linux-mediatek@lists.infradead.org,
	peter.wang@mediatek.com, alim.akhtar@samsung.com,
	matthias.bgg@gmail.com, beanhuo@micron.com,
	pedrom.sousa@synopsys.com, linux-arm-kernel@lists.infradead.org,
	bvanassche@acm.org
In-Reply-To: <MN2PR04MB6991A6F223D9C711A3D00B21FCB10@MN2PR04MB6991.namprd04.prod.outlook.com>

Hi Avri,

On Wed, 2019-09-11 at 10:58 +0000, Avri Altman wrote:
> > 
> > Enable auto suspend capability in MediaTek UFS driver.
> > 
> > Signed-off-by: Stanley Chu <stanley.chu@mediatek.com>
> Reviewed-by: Avri Altman <avri.altman@wdc.com>
> 
> > ---
> >  drivers/scsi/ufs/ufs-mediatek.c | 7 +++++++
> >  1 file changed, 7 insertions(+)
> > 
> > diff --git a/drivers/scsi/ufs/ufs-mediatek.c b/drivers/scsi/ufs/ufs-mediatek.c
> > index 0f6ff33ce52e..b7b177c6194c 100644
> > --- a/drivers/scsi/ufs/ufs-mediatek.c
> > +++ b/drivers/scsi/ufs/ufs-mediatek.c
> > @@ -117,6 +117,11 @@ static int ufs_mtk_setup_clocks(struct ufs_hba
> > *hba, bool on,
> >         return ret;
> >  }
> > 
> > +static void ufs_mtk_set_caps(struct ufs_hba *hba) {
> > +       hba->caps |= UFSHCD_CAP_RPM_AUTOSUSPEND; }
> Even a one-liner deserve new line for its closing brackets

The wired format is just happening the same as
[PATCH v1 2/3] scsi: ufs: override auto suspend tunables for ufs

It looks fine in patchwork website:
https://patchwork.kernel.org/patch/11140757/

I'll try to fix it in v2.

Thanks,
Stanley




_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* RE: [PATCH v1 2/3] scsi: ufs: override auto suspend tunables for ufs
From: Stanley Chu @ 2019-09-12  5:37 UTC (permalink / raw)
  To: Avri Altman
  Cc: sthumma@codeaurora.org, linux-scsi@vger.kernel.org,
	martin.petersen@oracle.com, marc.w.gonzalez@free.fr,
	vivek.gautam@codeaurora.org, andy.teng@mediatek.com,
	jejb@linux.ibm.com, chun-hung.wu@mediatek.com,
	kuohong.wang@mediatek.com, evgreen@chromium.org,
	subhashj@codeaurora.org, linux-mediatek@lists.infradead.org,
	peter.wang@mediatek.com, alim.akhtar@samsung.com,
	matthias.bgg@gmail.com, beanhuo@micron.com,
	pedrom.sousa@synopsys.com, linux-arm-kernel@lists.infradead.org,
	bvanassche@acm.org
In-Reply-To: <MN2PR04MB6991D63EEF50367BE2CB062CFCB10@MN2PR04MB6991.namprd04.prod.outlook.com>

Hi Avri,

> > diff --git a/drivers/scsi/ufs/ufshcd.c b/drivers/scsi/ufs/ufshcd.c index
> > 30b752c61b97..d253a018a73b 100644
> > --- a/drivers/scsi/ufs/ufshcd.c
> > +++ b/drivers/scsi/ufs/ufshcd.c
> > @@ -88,6 +88,9 @@
> >  /* Interrupt aggregation default timeout, unit: 40us */
> >  #define INT_AGGR_DEF_TO        0x02
> > 
> > +/* default delay of autosuspend: 2000 ms */ #define
> Typo?
> 

This is wired because it looks fine in both my local patch and in
patchwork website: https://patchwork.kernel.org/patch/11140759/

Anyway I will try to fix and check it carefully in v2.

Thanks,
Stanley


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH] aarch64/mm: speedup memory initialisation
From: Hubert Ralf @ 2019-09-12  5:36 UTC (permalink / raw)
  To: james.morse@arm.com; +Cc: linux-arm-kernel@lists.infradead.org
In-Reply-To: <93e5d420-91b7-0e42-7d3f-776323abe450@arm.com>

Hi James,
On 09/11/2019, 17:22 +0100 James Morse wrote:
> Hi Hubert,
> 
> (Subject-Nit: The prefix for this part of the kernel is 'arm64: mm:'. 
> git log --oneline $file will usually give you enough examples you can 
> spot the pattern.)
Thanks for the hint.
> 
> On 9/10/19 9:59 AM, Hubert Ralf wrote:
> > On ARM64 memmap_init_zone is used during bootmem_init, which iterates over
> > all pages in the memory starting at the lowest address until the highest
> > address is reached. On arm64 this ends up in searching a memmory region
> > containing for each single page between lowest and highest available
> > physicall address.
> > Having a sparse memory system there may be some big holes in the
> > memory map. For each page in this holes a lookup is done, which is
> > implemented as a binary search on the available memory blocks.
> > 
> > Adding a memmap_init for aarch64 to do the init only for the available
> > memory areas reduces the time needed for initialising memory on startup.
> > On a Renesas R-CAR M3 based system with a total hole of 20GB bootmem_init
> > execution time is reduced from 378ms to 84ms.
> 
> Hmm, there is nothing arm64 specific about this SPARSEMEM behaviour.
> Is there any reason this can't be done in core code, where it would 
> benefit other architectures too?
I'll try to move this to the core code.
> 
> (You'd need it to depend on !ARCH_DISCARD_MEMBLOCK as it looks like 
> memory-hotplug uses this late).
> 
> 
> Thanks,
> 
> James
Thanks,
Ralf
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH V7 3/3] arm64/mm: Enable memory hot remove
From: Anshuman Khandual @ 2019-09-12  4:28 UTC (permalink / raw)
  To: Catalin Marinas
  Cc: mark.rutland, mhocko, david, linux-mm, arunks, cpandya, ira.weiny,
	will, steven.price, valentin.schneider, suzuki.poulose,
	Robin.Murphy, broonie, cai, ard.biesheuvel, dan.j.williams,
	linux-arm-kernel, osalvador, steve.capper, logang, linux-kernel,
	akpm, mgorman
In-Reply-To: <20190910161759.GI14442@C02TF0J2HF1T.local>



On 09/10/2019 09:47 PM, Catalin Marinas wrote:
> On Tue, Sep 03, 2019 at 03:15:58PM +0530, Anshuman Khandual wrote:
>> @@ -770,6 +1022,28 @@ int __meminit vmemmap_populate(unsigned long start, unsigned long end, int node,
>>  void vmemmap_free(unsigned long start, unsigned long end,
>>  		struct vmem_altmap *altmap)
>>  {
>> +#ifdef CONFIG_MEMORY_HOTPLUG
>> +	/*
>> +	 * FIXME: We should have called remove_pagetable(start, end, true).
>> +	 * vmemmap and vmalloc virtual range might share intermediate kernel
>> +	 * page table entries. Removing vmemmap range page table pages here
>> +	 * can potentially conflict with a concurrent vmalloc() allocation.
>> +	 *
>> +	 * This is primarily because vmalloc() does not take init_mm ptl for
>> +	 * the entire page table walk and it's modification. Instead it just
>> +	 * takes the lock while allocating and installing page table pages
>> +	 * via [p4d|pud|pmd|pte]_alloc(). A concurrently vanishing page table
>> +	 * entry via memory hot remove can cause vmalloc() kernel page table
>> +	 * walk pointers to be invalid on the fly which can cause corruption
>> +	 * or worst, a crash.
>> +	 *
>> +	 * So free_empty_tables() gets called where vmalloc and vmemmap range
>> +	 * do not overlap at any intermediate level kernel page table entry.
>> +	 */
>> +	unmap_hotplug_range(start, end, true);
>> +	if (!vmalloc_vmemmap_overlap)
>> +		free_empty_tables(start, end);
>> +#endif
>>  }
>>  #endif	/* CONFIG_SPARSEMEM_VMEMMAP */

Hello Catalin,

> 
> I wonder whether we could simply ignore the vmemmap freeing altogether,
> just leave it around and not unmap it. This way, we could call

This would have been an option (even if we just ignore for a moment that
it might not be the cleanest possible method) if present memory hot remove
scenarios involved just system RAM of comparable sizes.

But with persistent memory which will be plugged in as ZONE_DEVICE might
ask for a vmem_atlamp based vmemmap mapping where the backing memory comes
from the persistent memory range itself not from existing system RAM. IIRC
altmap support was originally added because the amount persistent memory on
a system might be order of magnitude higher than that of regular system RAM.
During normal memory hot add (without altmap) would have caused great deal
of consumption from system RAM just for persistent memory range's vmemmap
mapping. In order to avoid such a scenario altmap was created to allocate
vmemmap mapping backing memory from the device memory range itself.

In such cases vmemmap must be unmapped and it's backing memory freed up for
the complete removal of persistent memory which originally requested for
altmap based vmemmap backing.

Just as a reference, the upcoming series which enables altmap support on
arm64 tries to allocate vmemmap mapping backing memory from the device range
itself during memory hot add and free them up during memory hot remove. Those
methods will not be possible if memory hot-remove does not really free up
vmemmap backing storage.

https://patchwork.kernel.org/project/linux-mm/list/?series=139299

> unmap_kernel_range() for removing the linear map and we save some code.
> 
> For the linear map, I think we use just above 2MB of tables for 1GB of
> memory mapped (worst case with 4KB pages we need 512 pte pages). For
> vmemmap we'd use slightly above 2MB for a 64GB hotplugged memory. Do we

You are right, the amount of memory required for kernel page table pages
are dependent on mapping page size and size of the range to be mapped. But
as explained below there might be hot remove situations where these ranges
will remain unused for ever after hot remove. There are chances that some
these pages (even empty) might remain unused for good.

> expect such memory to be re-plugged again in the same range? If we do,
> then I shouldn't even bother with removing the vmmemmap.
> 
> I don't fully understand the use-case for memory hotremove, so any
> additional info would be useful to make a decision here.

Sure, these are some of the scenarios I could recollect.

Physical Environment:

A. Physical DIMM replacement

Platform detects memory errors and initiates a DIMM replacement.

- Hot remove selected DIMM with errors
- Hot add a new DIMM in it's place on the same slot

In normal circumstances, the new DIMM will require the same linear
and vmemmap mapping. In such cases hot-remove could just unmap
linear mapping, leave everything else and be done with it. Though
I am not sure whether its a good idea to leave aside accessible
struct pages which correspond to non-present pfns.

B. Physical DIMM movement

Platform can detect errors on a DIMM slot itself and initiates a
DIMM movement into a different empty slot

- Hot remove selected memory DIMM from defective slot
- Hot add same memory DIMM into a different available empty slot

Physical address range for the DIMM has now changed, it will require
different linear and vmemmap mapping than what it had originally.
Hence during hot remove we should not only unmap linear and vmemmap
mapping but also free up all associated resources as this physical
memory range is never going to be available again because the slot
has gone bad permanently.

C. Physical DIMM hot-remove

Platform just initiates hot-remove of a DIMM and reduces available
memory as instructed by the administrator.

- Hot remove a selected DIMM

This memory might never come back again or comes back on a different
slot. Without that certainty, its is always better to unmap both linear
and vmemmap mappings, free up all associated resources.

D. Changing NUMA affinity

After performance analysis, administrator through the platform initiates
a DIMM hot-remove from a given node and a DIMM hot-add to another node
to achieve better NUMA affinity.

- Hot remove a selected DIMM from node N0
- Hot add selected DIMM to another node N1

Here both linear and vmemmap ranges will change after the movement and
there is uncertainty regarding whether the now empty physical range on
node N0 will ever get populated again. Without that certainty, its is
always better to unmap both linear and vmemmap mapping, free up all
associated resources.

Virtual Environment:

1. Memory hot-remove can just be initiated by the admin from the host in
order to reduce total physical memory entitlement of a guest which will
reflect any changing hosting contracts etc. The memory might never come
back again and in such cases hot-remove should be as clean freeing all
associated resources.

2. Memory hot-remove on the guest can be initiated from the host after
detecting memory errors on the backing physical DIMM. Memory hot-remove
on the guest will be followed by memory hot-remove on the host itself.
Replacement DIMM can be on the same slot taking over the same physical
address range from host as before but guest might get back it's memory
either on the same range previously or on some other guest physical
range.

3. Changing NUMA binding for a guest on the host might require guest
PFN realignment with respect to guest nodes as well.

Persistent Memory:

As mentioned previously, persistent memory has special vmemmap mapping
requirements through vmem_altmap which would need freeing up backing
memory from it's own range, for it to be completely removed.

Device memory (FPGA cards, GPU cards, Network cards etc):

In future, some of these coherent device memory might be plugged into
ZONE_DEVICE and managed through drivers. They might be attached to the
system via upcoming interfaces like CCIX. The managing drivers might
need to offline the device memory range in order to service some high
priority error, re-init and plug it back on a different physical range
due to existing CCIX link errors or some other constraints.

The point I am trying to make here is that there are many such possible
combinations of events with respect to memory hot-remove in both physical
and virtual environment for system RAM, persistent memory and other coherent
device memory. Leaving aside kernel page table pages or even struct pages
for unavailable (possibly forever) physical range might problematic. IMHO
it is better to do this as much cleanly as possible.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v3 2/2] drm/bridge: add it6505 driver
From: allen @ 2019-09-12  3:32 UTC (permalink / raw)
  Cc: Jernej Skrabec, Jitao Shi, Daniel Vetter, Jau-Chih Tseng,
	Yilun Lin, Allen Chen, David Airlie, Neil Armstrong, open list,
	open list:DRM DRIVERS, Andrzej Hajda, Jonas Karlman,
	moderated list:ARM/Mediatek SoC support, Laurent Pinchart,
	Pi-Hsun Shih, Matthias Brugger,
	moderated list:ARM/Mediatek SoC support
In-Reply-To: <1568259199-5827-1-git-send-email-allen.chen@ite.com.tw>

From: Allen Chen <allen.chen@ite.com.tw>

This adds support for the iTE IT6505.
This device can convert DPI signal to DP output.

Signed-off-by: Jitao Shi <jitao.shi@mediatek.com>
Signed-off-by: Yilun Lin <yllin@google.com>
Signed-off-by: Allen Chen <allen.chen@ite.com.tw>
Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>
---
 drivers/gpu/drm/bridge/Kconfig      |    7 +
 drivers/gpu/drm/bridge/Makefile     |    1 +
 drivers/gpu/drm/bridge/ite-it6505.c | 2531 +++++++++++++++++++++++++++++++++++
 3 files changed, 2539 insertions(+)
 create mode 100644 drivers/gpu/drm/bridge/ite-it6505.c

diff --git a/drivers/gpu/drm/bridge/Kconfig b/drivers/gpu/drm/bridge/Kconfig
index 1cc9f50..d8d7d28 100644
--- a/drivers/gpu/drm/bridge/Kconfig
+++ b/drivers/gpu/drm/bridge/Kconfig
@@ -45,6 +45,13 @@ config DRM_DUMB_VGA_DAC
 	  Support for non-programmable RGB to VGA DAC bridges, such as ADI
 	  ADV7123, TI THS8134 and THS8135 or passive resistor ladder DACs.
 
+config DRM_ITE_IT6505
+	tristate "ITE IT6505 DP bridge"
+	depends on OF
+	select DRM_KMS_HELPER
+	help
+	  ITE IT6505 DP bridge chip driver.
+
 config DRM_LVDS_ENCODER
 	tristate "Transparent parallel to LVDS encoder support"
 	depends on OF
diff --git a/drivers/gpu/drm/bridge/Makefile b/drivers/gpu/drm/bridge/Makefile
index 4934fcf..f5abca5 100644
--- a/drivers/gpu/drm/bridge/Makefile
+++ b/drivers/gpu/drm/bridge/Makefile
@@ -2,6 +2,7 @@
 obj-$(CONFIG_DRM_ANALOGIX_ANX78XX) += analogix-anx78xx.o
 obj-$(CONFIG_DRM_CDNS_DSI) += cdns-dsi.o
 obj-$(CONFIG_DRM_DUMB_VGA_DAC) += dumb-vga-dac.o
+obj-$(CONFIG_DRM_ITE_IT6505) += ite-it6505.o
 obj-$(CONFIG_DRM_LVDS_ENCODER) += lvds-encoder.o
 obj-$(CONFIG_DRM_MEGACHIPS_STDPXXXX_GE_B850V3_FW) += megachips-stdpxxxx-ge-b850v3-fw.o
 obj-$(CONFIG_DRM_NXP_PTN3460) += nxp-ptn3460.o
diff --git a/drivers/gpu/drm/bridge/ite-it6505.c b/drivers/gpu/drm/bridge/ite-it6505.c
new file mode 100644
index 0000000..5e046f6
--- /dev/null
+++ b/drivers/gpu/drm/bridge/ite-it6505.c
@@ -0,0 +1,2531 @@
+// SPDX-License-Identifier: GPL-2.0
+/*
+ * Copyright (c) 2018, The Linux Foundation. All rights reserved.
+ */
+#include <linux/bits.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/extcon.h>
+#include <linux/fs.h>
+#include <linux/gpio/consumer.h>
+#include <linux/i2c.h>
+#include <linux/interrupt.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/regmap.h>
+#include <linux/regulator/consumer.h>
+#include <linux/types.h>
+
+#include <crypto/hash.h>
+#include <crypto/sha.h>
+
+#include <drm/drm_atomic_helper.h>
+#include <drm/drm_crtc.h>
+#include <drm/drm_crtc_helper.h>
+#include <drm/drm_dp_helper.h>
+#include <drm/drm_edid.h>
+
+#define AX 0
+#define BX 1
+#define AUDSEL I2S
+#define AUDTYPE LPCM
+#define AUDFS AUD48K
+#define AUDCH 2
+/* 0: Standard I2S;1: 32bit I2S */
+#define I2SINPUTFMT 1
+/* 0: Left-justified;1: Right-justified */
+#define I2SJUSTIFIED 0
+/* 0: Data delay 1T correspond to WS;1: No data delay correspond to WS */
+#define I2SDATADELAY 0
+/* 0: is left channel;1: is right channel */
+#define I2SWSCHANNEL 0
+/* 0: MSB shift first;1: LSB shift first */
+#define I2SDATASEQ 0
+
+#define LANESWAP 0
+#define LANE 4
+#define _HBR 1
+#define ENSSC 1
+#define FLAGTRAINDOWN 150
+#define POLLINGKSVLIST 400
+#define TRAINFAILCNT 5
+#define TRAINFAILHPD 3
+#define AUX_WAIT_TIMEOUT_MS 15
+#define PCLK_DELAY 1
+#define PCLK_INV 0
+#define EDIDRETRYTIME 5
+#define SHOWVIDEOTIMING 2
+#define PWROFFRETRYTIME 5
+#define MAXPCLK 80000
+#define DEFAULTHDCP 1
+#define DEFAULTAUDIO 0
+#define DEFAULTPWRONOFF 1
+#define DEFAULTDRVHOLD 0
+#define DEFAULTPWRON 0
+#define AUX_FIFO_MAX_SIZE 0x10
+
+/* AX or BX */
+#define CHIP_VERSION BX
+
+/*
+ * 0: for bitland
+ * 1: for google kukui p2, huaqin
+ */
+#define AFE_SETTING 1
+
+static u8 afe_setting_table[2][3] = {
+	{0, 0, 0},
+	{0x93, 0x2a, 0x85}
+};
+
+enum sys_status {
+	SYS_UNPLUG = 0,
+	SYS_HPD,
+	SYS_AUTOTRAIN,
+	SYS_WAIT,
+	SYS_TRAINFAIL,
+	SYS_ReHDCP,
+	SYS_NOROP,
+	SYS_Unknown,
+};
+
+enum it6505_aud_sel {
+	I2S = 0,
+	SPDIF,
+};
+
+enum it6505_aud_fs {
+	AUD24K = 0x6,
+	AUD32K = 0x3,
+	AUD48K = 0x2,
+	AUD96K = 0xA,
+	AUD192K = 0xE,
+	AUD44P1K = 0x0,
+	AUD88P2K = 0x8,
+	AUD176P4K = 0xC,
+};
+
+enum it6505_aud_type {
+	LPCM = 0,
+	NLPCM,
+	DSS,
+	HBR,
+};
+
+enum aud_word_length {
+	AUD16BIT = 0,
+	AUD18BIT,
+	AUD20BIT,
+	AUD24BIT,
+};
+
+/* Audio Sample Word Length: AUD16BIT, AUD18BIT, AUD20BIT, AUD24BIT */
+#define AUDWORDLENGTH AUD24BIT
+
+struct it6505_platform_data {
+	struct regulator *pwr18;
+	struct regulator *ovdd;
+	struct gpio_desc *gpiod_hpd;
+	struct gpio_desc *gpiod_reset;
+};
+
+struct it6505 {
+	struct drm_dp_aux aux;
+	struct drm_bridge bridge;
+	struct i2c_client *client;
+	struct edid *edid;
+	struct drm_connector connector;
+	struct drm_dp_link link;
+	struct it6505_platform_data pdata;
+	struct mutex lock;
+	struct mutex mode_lock;
+	struct regmap *regmap;
+	struct drm_display_mode vid_info;
+
+	struct notifier_block event_nb;
+	struct extcon_dev *extcon;
+	struct work_struct extcon_wq;
+	enum sys_status status;
+	bool hbr;
+	u8 en_ssc;
+	bool laneswap_disabled;
+	bool laneswap;
+
+	enum it6505_aud_sel aud_sel;
+	enum it6505_aud_fs aud_fs;
+	enum it6505_aud_type aud_type;
+	u8 aud_ch;
+	u8 i2s_input_fmt;
+	u8 i2s_justified;
+	u8 i2s_data_delay;
+	u8 i2s_ws_channel;
+	u8 i2s_data_seq;
+	u8 vidstable_done;
+	enum aud_word_length audwordlength;
+	unsigned int en_hdcp;
+	unsigned int en_pwronoff;
+	unsigned int en_audio;
+	u8 cntfsm;
+	u8 train_fail_hpd;
+	bool cp_capable;
+	bool cp_done;
+	u8 downstream_repeater;
+	u8 shainput[64];
+	u8 av[5][4];
+	u8 bv[5][4];
+	bool powered;
+	/* it6505 driver hold option */
+	unsigned int drv_hold;
+};
+
+static const struct regmap_range it6505_bridge_volatile_ranges[] = {
+	{ .range_min = 0, .range_max = 0xFF },
+};
+
+static const struct regmap_access_table it6505_bridge_volatile_table = {
+	.yes_ranges = it6505_bridge_volatile_ranges,
+	.n_yes_ranges = ARRAY_SIZE(it6505_bridge_volatile_ranges),
+};
+
+static const struct regmap_config it6505_bridge_regmap_config = {
+	.reg_bits = 8,
+	.val_bits = 8,
+	.volatile_table = &it6505_bridge_volatile_table,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int dptxrd(struct it6505 *it6505, unsigned int reg_addr,
+		  unsigned int *value)
+{
+	int err;
+	struct device *dev = &it6505->client->dev;
+
+	err = regmap_read(it6505->regmap, reg_addr, value);
+	if (err < 0) {
+		DRM_DEV_ERROR(dev, "read failed reg[0x%x] err: %d", reg_addr,
+			      err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void it6505_dump(struct it6505 *it6505)
+{
+	unsigned int temp[16], i, j;
+	u8 value[16];
+	struct device *dev = &it6505->client->dev;
+
+	for (i = 0; i <= 0xff; i += 16) {
+		for (j = 0; j < 16; j++) {
+			dptxrd(it6505, i + j, temp + j);
+			value[j] = temp[j];
+		}
+		DRM_DEV_DEBUG_DRIVER(dev, "[0x%02x] = %16ph", i, value);
+	}
+}
+
+static int dptxwr(struct it6505 *it6505, unsigned int reg_addr,
+		  unsigned int reg_val)
+{
+	int err;
+	struct device *dev = &it6505->client->dev;
+
+	err = regmap_write(it6505->regmap, reg_addr, reg_val);
+
+	if (err < 0) {
+		DRM_DEV_ERROR(dev, "write failed reg[0x%x] = 0x%x err = %d",
+			      reg_addr, reg_val, err);
+		return err;
+	}
+
+	return 0;
+}
+
+static int dptxset(struct it6505 *it6505, unsigned int reg, unsigned int mask,
+		   unsigned int value)
+{
+	int err;
+	struct device *dev = &it6505->client->dev;
+
+	err = regmap_update_bits(it6505->regmap, reg, mask, value);
+	if (err < 0) {
+		DRM_DEV_ERROR(
+			dev, "write reg[0x%x] = 0x%x mask = 0x%x failed err %d",
+			reg, value, mask, err);
+		return err;
+	}
+
+	return 0;
+}
+
+static void dptx_debug_print(struct it6505 *it6505, unsigned int reg,
+			     const char *prefix)
+{
+	unsigned int val;
+	int err;
+	struct device *dev = &it6505->client->dev;
+
+	if (likely(!(drm_debug & DRM_UT_DRIVER)))
+		return;
+
+	err = dptxrd(it6505, reg, &val);
+	if (err < 0)
+		DRM_DEV_DEBUG_DRIVER(dev, "%s reg%02x read error", prefix, reg);
+	else
+		DRM_DEV_DEBUG_DRIVER(dev, "%s reg%02x = 0x%02x", prefix, reg,
+				     val);
+}
+
+static inline struct it6505 *connector_to_it6505(struct drm_connector *c)
+{
+	return container_of(c, struct it6505, connector);
+}
+
+static inline struct it6505 *bridge_to_it6505(struct drm_bridge *bridge)
+{
+	return container_of(bridge, struct it6505, bridge);
+}
+
+static void it6505_init_fsm(struct it6505 *it6505)
+{
+	it6505->aud_sel = AUDSEL;
+	it6505->aud_fs = AUDFS;
+	it6505->aud_ch = AUDCH;
+	it6505->aud_type = AUDTYPE;
+	it6505->i2s_input_fmt = I2SINPUTFMT;
+	it6505->i2s_justified = I2SJUSTIFIED;
+	it6505->i2s_data_delay = I2SDATADELAY;
+	it6505->i2s_ws_channel = I2SWSCHANNEL;
+	it6505->i2s_data_seq = I2SDATASEQ;
+	it6505->audwordlength = AUDWORDLENGTH;
+	it6505->en_audio = DEFAULTAUDIO;
+	it6505->en_hdcp = DEFAULTHDCP;
+
+	it6505->hbr = _HBR;
+	it6505->en_ssc = ENSSC;
+	it6505->laneswap = LANESWAP;
+	it6505->vidstable_done = 0;
+}
+
+static void it6505_termination_on(struct it6505 *it6505)
+{
+#if (CHIP_VERSION == BX)
+	dptxset(it6505, 0x5D, 0x80, 0x00);
+	dptxset(it6505, 0x5E, 0x02, 0x02);
+#endif
+}
+
+static void it6505_termination_off(struct it6505 *it6505)
+{
+#if (CHIP_VERSION == BX)
+	dptxset(it6505, 0x5D, 0x80, 0x80);
+	dptxset(it6505, 0x5E, 0x02, 0x00);
+	dptxset(it6505, 0x5C, 0xF0, 0x00);
+#endif
+}
+
+static bool dptx_getsinkhpd(struct it6505 *it6505)
+{
+	unsigned int value;
+	int ret;
+
+	ret = dptxrd(it6505, 0x0D, &value);
+
+	if (ret < 0)
+		return false;
+
+	return (value & BIT(1)) == BIT(1);
+}
+
+static void dptx_chgbank(struct it6505 *it6505, unsigned int bank_id)
+{
+	dptxset(it6505, 0x0F, 0x01, bank_id & BIT(0));
+}
+
+static void it6505_int_mask_on(struct it6505 *it6505)
+{
+	dptxwr(it6505, 0x09, 0x1F);
+	dptxwr(it6505, 0x0A, 0x07);
+	dptxwr(it6505, 0x0B, 0x90);
+}
+
+static void it6505_int_mask_off(struct it6505 *it6505)
+{
+	dptxwr(it6505, 0x09, 0x00);
+	dptxwr(it6505, 0x0A, 0x00);
+	dptxwr(it6505, 0x0B, 0x00);
+}
+
+static void dptx_init(struct it6505 *it6505)
+{
+	dptxwr(it6505, 0x05, 0x3B);
+	usleep_range(1000, 2000);
+	dptxwr(it6505, 0x05, 0x1F);
+	usleep_range(1000, 1500);
+}
+
+static void it6505_init_and_mask_on(struct it6505 *it6505)
+{
+	dptx_init(it6505);
+	it6505_int_mask_on(it6505);
+}
+
+static int it6505_poweron(struct it6505 *it6505)
+{
+	struct it6505_platform_data *pdata = &it6505->pdata;
+	int err = 0;
+	struct device *dev = &it6505->client->dev;
+
+	if (it6505->powered) {
+		DRM_DEV_DEBUG_DRIVER(dev, "it6505 already powered on");
+		return 0;
+	}
+
+	DRM_DEV_DEBUG_DRIVER(dev, "it6505 start to power on");
+
+	err = regulator_enable(pdata->pwr18);
+	DRM_DEV_DEBUG_DRIVER(dev, "%s to enable pwr18 regulator",
+			     err ? "Failed" : "Succeeded");
+	if (err)
+		return err;
+	/* time interval between IVDD and OVDD at least be 1ms */
+	usleep_range(1000, 2000);
+	err = regulator_enable(pdata->ovdd);
+	DRM_DEV_DEBUG_DRIVER(dev, "%s to enable ovdd regulator",
+			     err ? "Failed" : "Succeeded");
+	if (err) {
+		regulator_disable(pdata->pwr18);
+		return err;
+	}
+	/* time interval between OVDD and SYSRSTN at least be 10ms */
+	usleep_range(10000, 20000);
+	gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
+	usleep_range(1000, 2000);
+	gpiod_set_value_cansleep(pdata->gpiod_reset, 1);
+	usleep_range(10000, 20000);
+
+	it6505_init_and_mask_on(it6505);
+	it6505->powered = true;
+	return 0;
+}
+
+static int it6505_poweroff(struct it6505 *it6505)
+{
+	struct it6505_platform_data *pdata = &it6505->pdata;
+	int err = 0;
+	struct device *dev = &it6505->client->dev;
+
+	if (!it6505->powered) {
+		DRM_DEV_DEBUG_DRIVER(dev, "power had been already off");
+		return 0;
+	}
+	gpiod_set_value_cansleep(pdata->gpiod_reset, 0);
+	err = regulator_disable(pdata->pwr18);
+	DRM_DEV_DEBUG_DRIVER(dev, "%s to disable pwr18 regulator",
+			     err ? "Failed" : "Succeeded");
+	if (err)
+		return err;
+	err = regulator_disable(pdata->ovdd);
+	DRM_DEV_DEBUG_DRIVER(dev, "%s to disable ovdd regulator",
+			     err ? "Failed" : "Succeeded");
+	if (err)
+		return err;
+
+	kfree(it6505->edid);
+	it6505->edid = NULL;
+	it6505->powered = false;
+	return 0;
+}
+
+static void show_vid_info(struct it6505 *it6505)
+{
+	int hsync_pol, vsync_pol, interlaced;
+	int htotal, hdes, hdew, hfph, hsyncw;
+	int vtotal, vdes, vdew, vfph, vsyncw;
+	int rddata, rddata1, i;
+	int pclk, sum;
+
+	usleep_range(10000, 15000);
+	dptx_chgbank(it6505, 0);
+	dptxrd(it6505, 0xa0, &rddata);
+	hsync_pol = rddata & BIT(0);
+	vsync_pol = (rddata & BIT(2)) >> 2;
+	interlaced = (rddata & BIT(4)) >> 4;
+
+	dptxrd(it6505, 0xa1, &rddata);
+	dptxrd(it6505, 0xa2, &rddata1);
+	htotal = ((rddata1 & 0x1F) << 8) + rddata;
+
+	dptxrd(it6505, 0xa3, &rddata);
+	dptxrd(it6505, 0xa4, &rddata1);
+
+	hdes = ((rddata1 & 0x1F) << 8) + rddata;
+
+	dptxrd(it6505, 0xa5, &rddata);
+	dptxrd(it6505, 0xa6, &rddata1);
+
+	hdew = ((rddata1 & 0x1F) << 8) + rddata;
+
+	dptxrd(it6505, 0xa7, &rddata);
+	dptxrd(it6505, 0xa8, &rddata1);
+
+	hfph = ((rddata1 & 0x1F) << 8) + rddata;
+
+	dptxrd(it6505, 0xa9, &rddata);
+	dptxrd(it6505, 0xaa, &rddata1);
+
+	hsyncw = ((rddata1 & 0x1F) << 8) + rddata;
+
+	dptxrd(it6505, 0xab, &rddata);
+	dptxrd(it6505, 0xac, &rddata1);
+	vtotal = ((rddata1 & 0x0F) << 8) + rddata;
+
+	dptxrd(it6505, 0xad, &rddata);
+	dptxrd(it6505, 0xae, &rddata1);
+	vdes = ((rddata1 & 0x0F) << 8) + rddata;
+
+	dptxrd(it6505, 0xaf, &rddata);
+	dptxrd(it6505, 0xb0, &rddata1);
+	vdew = ((rddata1 & 0x0F) << 8) + rddata;
+
+	dptxrd(it6505, 0xb1, &rddata);
+	dptxrd(it6505, 0xb2, &rddata1);
+	vfph = ((rddata1 & 0x0F) << 8) + rddata;
+
+	dptxrd(it6505, 0xb3, &rddata);
+	dptxrd(it6505, 0xb4, &rddata1);
+	vsyncw = ((rddata1 & 0x0F) << 8) + rddata;
+
+	sum = 0;
+	for (i = 0; i < 100; i++) {
+		dptxset(it6505, 0x12, 0x80, 0x80);
+		usleep_range(10000, 15000);
+		dptxset(it6505, 0x12, 0x80, 0x00);
+
+		dptxrd(it6505, 0x13, &rddata);
+		dptxrd(it6505, 0x14, &rddata1);
+		rddata = ((rddata1 & 0x0F) << 8) + rddata;
+
+		sum += rddata;
+	}
+
+	sum /= 100;
+	pclk = 13500 * 2048 / sum;
+	it6505->vid_info.clock = pclk;
+	it6505->vid_info.hdisplay = hdew;
+	it6505->vid_info.hsync_start = hdew + hfph;
+	it6505->vid_info.hsync_end = hdew + hfph + hsyncw;
+	it6505->vid_info.htotal = htotal;
+	it6505->vid_info.vdisplay = vdew;
+	it6505->vid_info.vsync_start = vdew + vfph;
+	it6505->vid_info.vsync_end = vdew + vfph + vsyncw;
+	it6505->vid_info.vtotal = vtotal;
+	it6505->vid_info.vrefresh = pclk / htotal / vtotal;
+
+	DRM_DEV_DEBUG_DRIVER(&it6505->client->dev, DRM_MODE_FMT,
+			     DRM_MODE_ARG(&it6505->vid_info));
+}
+
+static void show_aud_mcnt(struct it6505 *it6505)
+{
+	unsigned int audn, regde, regdf, rege0, vclk, aclk, audmcal, audmcnt;
+	struct device *dev = &it6505->client->dev;
+
+	dptxrd(it6505, 0xde, &regde);
+	dptxrd(it6505, 0xdf, &regdf);
+	dptxrd(it6505, 0xe0, &rege0);
+	audn = regde + (regdf << 8) + (rege0 << 16);
+	if (it6505->hbr)
+		vclk = 2700000;
+	else
+		vclk = 1620000;
+	switch (it6505->aud_fs) {
+	case AUD32K:
+		aclk = 320;
+		break;
+	case AUD48K:
+		aclk = 480;
+		break;
+	case AUD96K:
+		aclk = 960;
+		break;
+	case AUD192K:
+		aclk = 1920;
+		break;
+	case AUD44P1K:
+		aclk = 441;
+	case AUD88P2K:
+		aclk = 882;
+		break;
+	case AUD176P4K:
+		aclk = 1764;
+		break;
+	default:
+		aclk = 0;
+		break;
+	}
+	audmcal = audn * aclk / vclk * 512;
+	dptxrd(it6505, 0xe4, &regde);
+	dptxrd(it6505, 0xe5, &regdf);
+	dptxrd(it6505, 0xe6, &rege0);
+	audmcnt = (rege0 << 16) + (regdf << 8) + regde;
+	DRM_DEV_DEBUG_DRIVER(dev, "audio N:0x%06x", audn);
+	DRM_DEV_DEBUG_DRIVER(dev, "audio Mcal:0x%06x", audmcal);
+	DRM_DEV_DEBUG_DRIVER(dev, "audio Mcnt:0x%06x", audmcnt);
+}
+
+static const char *const state_string[] = {
+	[SYS_UNPLUG] = "SYS_UNPLUG",
+	[SYS_HPD] = "SYS_HPD",
+	[SYS_AUTOTRAIN] = "SYS_AUTOTRAIN",
+	[SYS_WAIT] = "SYS_WAIT",
+	[SYS_TRAINFAIL] = "SYS_TRAINFAIL",
+	[SYS_ReHDCP] = "SYS_ReHDCP",
+	[SYS_NOROP] = "SYS_NOROP",
+	[SYS_Unknown] = "SYS_Unknown",
+};
+
+static void dptx_sys_chg(struct it6505 *it6505, enum sys_status newstate)
+{
+	int i = 0;
+	struct device *dev = &it6505->client->dev;
+
+	if (newstate != SYS_UNPLUG) {
+		if (!dptx_getsinkhpd(it6505))
+			newstate = SYS_UNPLUG;
+	}
+	if (it6505->status == newstate)
+		return;
+
+	DRM_DEV_DEBUG_DRIVER(dev, "sys_state change: %s -> %s",
+			     state_string[it6505->status],
+			     state_string[newstate]);
+	it6505->status = newstate;
+
+	switch (it6505->status) {
+	case SYS_UNPLUG:
+		kfree(it6505->edid);
+		it6505->edid = NULL;
+		DRM_DEV_DEBUG_DRIVER(dev, "Free it6505 EDID memory");
+		it6505_init_and_mask_on(it6505);
+		it6505_termination_off(it6505);
+		break;
+	case SYS_HPD:
+		it6505_termination_on(it6505);
+		break;
+	case SYS_AUTOTRAIN:
+		break;
+	case SYS_WAIT:
+		break;
+	case SYS_ReHDCP:
+		break;
+	case SYS_NOROP:
+		for (i = 0; i < SHOWVIDEOTIMING; i++)
+			show_vid_info(it6505);
+		break;
+	case SYS_TRAINFAIL:
+		/* it6505 goes to idle */
+		break;
+	default:
+		break;
+	}
+}
+
+static bool it6505_aux_op_finished(struct it6505 *it6505)
+{
+	unsigned int value;
+	int err;
+
+	err = regmap_read(it6505->regmap, 0x2b, &value);
+	if (err < 0)
+		return false;
+
+	return (value & BIT(5)) == 0;
+}
+
+static int dptx_auxwait(struct it6505 *it6505)
+{
+	unsigned int status;
+	unsigned long timeout;
+	int err;
+	struct device *dev = &it6505->client->dev;
+
+	timeout = jiffies + msecs_to_jiffies(AUX_WAIT_TIMEOUT_MS) + 1;
+
+	while (!it6505_aux_op_finished(it6505)) {
+		if (time_after(jiffies, timeout)) {
+			DRM_DEV_ERROR(dev, "Timed out waiting AUX to finish");
+			return -ETIMEDOUT;
+		}
+		usleep_range(1000, 2000);
+	}
+
+	err = dptxrd(it6505, 0x9f, &status);
+	if (err < 0) {
+		DRM_DEV_ERROR(dev, "Failed to read AUX channel: %d", err);
+		return err;
+	}
+
+	if (status & 0x03) {
+		DRM_DEV_ERROR(dev, "Failed to wait for AUX (status: 0x%x)",
+			      status);
+		return -ETIMEDOUT;
+	}
+
+	return 0;
+}
+
+enum aux_cmd_type {
+	CMD_AUX_NATIVE_READ = 0x0,
+	CMD_AUX_NATIVE_WRITE = 0x5,
+	CMD_AUX_I2C_EDID_READ = 0xB,
+};
+
+enum aux_cmd_reply {
+	REPLY_ACK,
+	REPLY_NACK,
+	REPLY_DEFER,
+};
+
+static ssize_t it6505_aux_do_transfer(struct it6505 *it6505,
+				      enum aux_cmd_type cmd,
+				      unsigned int address, u8 *buffer,
+				      size_t size, enum aux_cmd_reply *reply)
+{
+	int ret;
+	int i;
+	int status, val;
+
+	if (cmd == CMD_AUX_I2C_EDID_READ) {
+		/* DP AUX EDID FIFO has maximum length of 16 bytes. */
+		size = min_t(size_t, size, AUX_FIFO_MAX_SIZE);
+		/* Enable AUX FIFO read back and clear FIFO */
+		dptxwr(it6505, 0x23, 0xC3);
+		dptxwr(it6505, 0x23, 0xC2);
+	} else {
+		/* The DP AUX transmit buffer has 4 bytes. */
+		size = min_t(size_t, size, 4);
+		dptxwr(it6505, 0x23, 0x42);
+	}
+
+	/* Start Address[7:0] */
+	dptxwr(it6505, 0x24, (address >> 0) & 0xFF);
+	/* Start Address[15:8] */
+	dptxwr(it6505, 0x25, (address >> 8) & 0xFF);
+	/* WriteNum[3:0]+StartAdr[19:16] */
+	dptxwr(it6505, 0x26, ((address >> 16) & 0x0F) | ((size - 1) << 4));
+
+	if (cmd == CMD_AUX_NATIVE_WRITE)
+		regmap_bulk_write(it6505->regmap, 0x27, buffer, size);
+
+	/* Aux Fire */
+	dptxwr(it6505, 0x2B, cmd);
+
+	ret = dptx_auxwait(it6505);
+	if (ret < 0)
+		return ret;
+
+	ret = dptxrd(it6505, 0x9F, &status);
+	if (ret < 0)
+		return ret;
+
+	switch ((status >> 6) & 0x3) {
+	case 0:
+		*reply = REPLY_ACK;
+		break;
+	case 1:
+		*reply = REPLY_NACK;
+		return 0;
+	case 2:
+		*reply = REPLY_DEFER;
+		return 0;
+	case 3:
+		return -ETIMEDOUT;
+	}
+
+	if (cmd == CMD_AUX_NATIVE_WRITE)
+		goto out;
+
+	if (cmd == CMD_AUX_I2C_EDID_READ) {
+		for (i = 0; i < size; i++) {
+			ret = dptxrd(it6505, 0x2F, &val);
+			if (ret < 0)
+				return ret;
+			buffer[i] = val;
+		}
+	} else {
+		for (i = 0; i < size; i++) {
+			ret = dptxrd(it6505, 0x2C + i, &val);
+			if (ret < 0)
+				return ret;
+			buffer[size - 1 - i] = val;
+		}
+	}
+
+out:
+	dptxwr(it6505, 0x23, 0x40);
+	return size;
+}
+
+static ssize_t it6505_aux_transfer(struct drm_dp_aux *aux,
+				   struct drm_dp_aux_msg *msg)
+{
+	struct it6505 *it6505 = container_of(aux, struct it6505, aux);
+	u8 cmd;
+	bool is_i2c = !(msg->request & DP_AUX_NATIVE_WRITE);
+	int ret;
+	enum aux_cmd_reply reply;
+
+	/* IT6505 doesn't support arbitrary I2C read / write. */
+	if (is_i2c)
+		return -EINVAL;
+
+	switch (msg->request) {
+	case DP_AUX_NATIVE_READ:
+		cmd = CMD_AUX_NATIVE_READ;
+		break;
+	case DP_AUX_NATIVE_WRITE:
+		cmd = CMD_AUX_NATIVE_WRITE;
+		break;
+	default:
+		return -EINVAL;
+	}
+
+	ret = it6505_aux_do_transfer(it6505, cmd, msg->address, msg->buffer,
+				     msg->size, &reply);
+	if (ret < 0)
+		return ret;
+
+	switch (reply) {
+	case REPLY_ACK:
+		msg->reply = DP_AUX_NATIVE_REPLY_ACK;
+		break;
+	case REPLY_NACK:
+		msg->reply = DP_AUX_NATIVE_REPLY_NACK;
+		break;
+	case REPLY_DEFER:
+		msg->reply = DP_AUX_NATIVE_REPLY_DEFER;
+		break;
+	}
+
+	return ret;
+}
+
+static int dptx_get_edidblock(void *data, u8 *buf, unsigned int blockno,
+			      size_t len)
+{
+	struct it6505 *it6505 = data;
+	int offset, ret;
+	struct device *dev = &it6505->client->dev;
+	enum aux_cmd_reply reply;
+
+	dptxset(it6505, 0x05, 0x08, 0x08);
+	dptxset(it6505, 0x05, 0x08, 0x00);
+	DRM_DEV_DEBUG_DRIVER(dev, "blocknum = %d", blockno);
+
+	for (offset = 0; offset < EDID_LENGTH; offset += 8) {
+		ret = it6505_aux_do_transfer(it6505, CMD_AUX_I2C_EDID_READ,
+					     blockno * EDID_LENGTH + offset,
+					     buf + offset, 8, &reply);
+		if (ret < 0)
+			return ret;
+		if (reply != REPLY_ACK)
+			return -EIO;
+
+		DRM_DEV_DEBUG_DRIVER(dev, "[0x%02x]: %8ph", offset,
+				     buf + offset);
+	}
+
+	return 0;
+}
+
+static int it6505_get_modes(struct drm_connector *connector)
+{
+	struct it6505 *it6505 = connector_to_it6505(connector);
+	int err, num_modes = 0;
+	struct device *dev = &it6505->client->dev;
+
+	it6505->train_fail_hpd = TRAINFAILHPD;
+	if (it6505->edid)
+		return drm_add_edid_modes(connector, it6505->edid);
+	mutex_lock(&it6505->mode_lock);
+
+	it6505_dump(it6505);
+	dptx_debug_print(it6505, 0x9F, "aux status");
+	it6505->edid =
+		drm_do_get_edid(&it6505->connector, dptx_get_edidblock, it6505);
+	if (!it6505->edid) {
+		DRM_DEV_ERROR(dev, "Failed to read EDID");
+		goto unlock;
+	}
+
+	err = drm_connector_update_edid_property(connector, it6505->edid);
+	if (err) {
+		DRM_DEV_ERROR(dev, "Failed to update EDID property: %d", err);
+		goto unlock;
+	}
+
+	num_modes = drm_add_edid_modes(connector, it6505->edid);
+
+unlock:
+	mutex_unlock(&it6505->mode_lock);
+
+	return num_modes;
+}
+
+static const struct drm_connector_helper_funcs it6505_connector_helper_funcs = {
+	.get_modes = it6505_get_modes,
+};
+
+static enum drm_connector_status it6505_detect(struct drm_connector *connector,
+					       bool force)
+{
+	struct it6505 *it6505 = connector_to_it6505(connector);
+
+	if (gpiod_get_value(it6505->pdata.gpiod_hpd))
+		return connector_status_disconnected;
+
+	return connector_status_connected;
+}
+
+static const struct drm_connector_funcs it6505_connector_funcs = {
+	.fill_modes = drm_helper_probe_single_connector_modes,
+	.detect = it6505_detect,
+	.destroy = drm_connector_cleanup,
+	.reset = drm_atomic_helper_connector_reset,
+	.atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
+	.atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
+};
+
+static int it6505_extcon_notifier(struct notifier_block *self,
+				  unsigned long event, void *ptr)
+{
+	struct it6505 *it6505 = container_of(self, struct it6505, event_nb);
+
+	schedule_work(&it6505->extcon_wq);
+	return NOTIFY_DONE;
+}
+
+static void it6505_extcon_work(struct work_struct *work)
+{
+	struct it6505 *it6505 = container_of(work, struct it6505, extcon_wq);
+	int state = extcon_get_state(it6505->extcon, EXTCON_DISP_DP);
+	unsigned int pwroffretry = 0;
+	struct device *dev = &it6505->client->dev;
+
+	if (it6505->drv_hold)
+		return;
+	mutex_lock(&it6505->lock);
+	DRM_DEV_DEBUG_DRIVER(dev, "EXTCON_DISP_DP = 0x%02x", state);
+	if (state > 0) {
+		DRM_DEV_DEBUG_DRIVER(dev, "start to power on");
+		msleep(1000);
+		it6505_poweron(it6505);
+		if (!dptx_getsinkhpd(it6505))
+			it6505_termination_off(it6505);
+	} else {
+		if (it6505->en_pwronoff) {
+			DRM_DEV_DEBUG_DRIVER(dev, "start to power off");
+			while (it6505_poweroff(it6505) &&
+			       pwroffretry++ < PWROFFRETRYTIME) {
+				DRM_DEV_DEBUG_DRIVER(dev,
+						     "power off fail %d times",
+						     pwroffretry);
+			}
+			drm_helper_hpd_irq_event(it6505->connector.dev);
+			DRM_DEV_DEBUG_DRIVER(dev, "power off it6505 success!");
+		}
+	}
+	mutex_unlock(&it6505->lock);
+}
+
+static int it6505_use_notifier_module(struct it6505 *it6505)
+{
+	int ret;
+	struct device *dev = &it6505->client->dev;
+
+	it6505->event_nb.notifier_call = it6505_extcon_notifier;
+	INIT_WORK(&it6505->extcon_wq, it6505_extcon_work);
+	ret = devm_extcon_register_notifier(&it6505->client->dev,
+					    it6505->extcon, EXTCON_DISP_DP,
+					    &it6505->event_nb);
+	if (ret) {
+		DRM_DEV_ERROR(dev, "failed to register notifier for DP");
+		return ret;
+	}
+	return 0;
+}
+
+static int it6505_bridge_attach(struct drm_bridge *bridge)
+{
+	struct it6505 *it6505 = bridge_to_it6505(bridge);
+	struct device *dev;
+	int err;
+
+	dev = &it6505->client->dev;
+	if (!bridge->encoder) {
+		DRM_DEV_ERROR(dev, "Parent encoder object not found");
+		return -ENODEV;
+	}
+
+	err = drm_connector_init(bridge->dev, &it6505->connector,
+				 &it6505_connector_funcs,
+				 DRM_MODE_CONNECTOR_DisplayPort);
+	if (err < 0) {
+		DRM_DEV_ERROR(dev, "Failed to initialize connector: %d", err);
+		return err;
+	}
+
+	drm_connector_helper_add(&it6505->connector,
+				 &it6505_connector_helper_funcs);
+
+	it6505->connector.polled = DRM_CONNECTOR_POLL_HPD;
+
+	err = drm_connector_attach_encoder(&it6505->connector, bridge->encoder);
+	if (err < 0) {
+		DRM_DEV_ERROR(dev, "Failed to link up connector to encoder: %d",
+			      err);
+		return err;
+	}
+
+	err = drm_connector_register(&it6505->connector);
+	if (err < 0) {
+		DRM_DEV_ERROR(dev, "Failed to register connector: %d", err);
+		return err;
+	}
+
+	err = it6505_use_notifier_module(it6505);
+	if (err < 0) {
+		drm_connector_unregister(&it6505->connector);
+		return err;
+	}
+	schedule_work(&it6505->extcon_wq);
+
+	return 0;
+}
+
+static void it6505_bridge_detach(struct drm_bridge *bridge)
+{
+	struct it6505 *it6505 = bridge_to_it6505(bridge);
+
+	devm_extcon_unregister_notifier(&it6505->client->dev, it6505->extcon,
+					EXTCON_DISP_DP, &it6505->event_nb);
+	flush_work(&it6505->extcon_wq);
+	drm_connector_unregister(&it6505->connector);
+}
+
+static enum drm_mode_status
+it6505_bridge_mode_valid(struct drm_bridge *bridge,
+			 const struct drm_display_mode *mode)
+{
+	if (mode->flags & DRM_MODE_FLAG_INTERLACE)
+		return MODE_NO_INTERLACE;
+
+	/* Max 1200p at 5.4 Ghz, one lane */
+	if (mode->clock > MAXPCLK)
+		return MODE_CLOCK_HIGH;
+
+	return MODE_OK;
+}
+
+static int it6505_send_video_infoframe(struct it6505 *it6505,
+				       struct hdmi_avi_infoframe *frame)
+{
+	u8 buffer[HDMI_INFOFRAME_HEADER_SIZE + HDMI_AVI_INFOFRAME_SIZE];
+	int err;
+	struct device *dev = &it6505->client->dev;
+
+	err = hdmi_avi_infoframe_pack(frame, buffer, sizeof(buffer));
+	if (err < 0) {
+		DRM_DEV_ERROR(dev, "Failed to pack AVI infoframe: %d\n", err);
+		return err;
+	}
+
+	err = dptxset(it6505, 0xe8, 0x01, 0x00);
+	if (err)
+		return err;
+
+	err = regmap_bulk_write(it6505->regmap, 0xe9,
+				buffer + HDMI_INFOFRAME_HEADER_SIZE,
+				frame->length);
+	if (err)
+		return err;
+
+	err = dptxset(it6505, 0xe8, 0x01, 0x01);
+	if (err)
+		return err;
+
+	return 0;
+}
+
+static void it6505_bridge_mode_set(struct drm_bridge *bridge,
+				   struct drm_display_mode *mode,
+				   struct drm_display_mode *adjusted_mode)
+{
+	struct it6505 *it6505 = bridge_to_it6505(bridge);
+	struct hdmi_avi_infoframe frame;
+	int err;
+	struct device *dev = &it6505->client->dev;
+
+	mutex_lock(&it6505->mode_lock);
+	err = drm_hdmi_avi_infoframe_from_display_mode(&frame, adjusted_mode,
+						       false);
+	if (err) {
+		DRM_DEV_ERROR(dev, "Failed to setup AVI infoframe: %d", err);
+		goto unlock;
+	}
+	it6505->vid_info.base.id = adjusted_mode->base.id;
+	strlcpy(it6505->vid_info.name, adjusted_mode->name,
+		DRM_DISPLAY_MODE_LEN);
+	it6505->vid_info.type = adjusted_mode->type;
+	it6505->vid_info.flags = adjusted_mode->flags;
+	err = it6505_send_video_infoframe(it6505, &frame);
+	if (err)
+		DRM_DEV_ERROR(dev, "Failed to send AVI infoframe: %d", err);
+
+unlock:
+	mutex_unlock(&it6505->mode_lock);
+}
+
+static void dptx_set_aud_fmt(struct it6505 *it6505)
+{
+	unsigned int audsrc;
+	/* I2S MODE */
+	dptxwr(it6505, 0xB9,
+	       (it6505->audwordlength << 5) | (it6505->i2s_data_seq << 4) |
+		       (it6505->i2s_ws_channel << 3) |
+		       (it6505->i2s_data_delay << 2) |
+		       (it6505->i2s_justified << 1) | it6505->i2s_input_fmt);
+	if (it6505->aud_sel == SPDIF) {
+		dptxwr(it6505, 0xBA, 0x00);
+		/* 0x30 = 128*FS */
+		dptxset(it6505, 0x11, 0xF0, 0x30);
+	} else {
+		dptxwr(it6505, 0xBA, 0xe4);
+	}
+
+	dptxwr(it6505, 0xBB, 0x20);
+	dptxwr(it6505, 0xBC, 0x00);
+	audsrc = 1;
+
+	if (it6505->aud_ch > 2)
+		audsrc |= 2;
+
+	if (it6505->aud_ch > 4)
+		audsrc |= 4;
+
+	if (it6505->aud_ch > 6)
+		audsrc |= 8;
+
+	audsrc |= it6505->aud_sel << 4;
+
+	dptxwr(it6505, 0xB8, audsrc);
+}
+
+static void dptx_set_aud_chsts(struct it6505 *it6505)
+{
+	enum it6505_aud_fs audfs = it6505->aud_fs;
+
+	/* Channel Status */
+	dptxwr(it6505, 0xBF, it6505->aud_type << 1);
+	dptxwr(it6505, 0xC0, 0x00);
+	dptxwr(it6505, 0xC1, 0x00);
+	dptxwr(it6505, 0xC2, audfs);
+	switch (it6505->audwordlength) {
+	case AUD16BIT:
+		dptxwr(it6505, 0xC3, (~audfs << 4) + 0x02);
+		break;
+
+	case AUD18BIT:
+		dptxwr(it6505, 0xC3, (~audfs << 4) + 0x04);
+		break;
+
+	case AUD20BIT:
+		dptxwr(it6505, 0xC3, (~audfs << 4) + 0x03);
+		break;
+
+	case AUD24BIT:
+		dptxwr(it6505, 0xC3, (~audfs << 4) + 0x0B);
+		break;
+	}
+}
+
+static void dptx_set_audio_infoframe(struct it6505 *it6505)
+{
+	struct device *dev = &it6505->client->dev;
+
+	dptxwr(it6505, 0xf7, it6505->aud_ch - 1);
+
+	switch (it6505->aud_ch) {
+	case 2:
+		dptxwr(it6505, 0xF9, 0x00);
+		break;
+	case 3:
+		dptxwr(it6505, 0xF9, 0x01);
+		break;
+	case 4:
+		dptxwr(it6505, 0xF9, 0x03);
+		break;
+	case 5:
+		dptxwr(it6505, 0xF9, 0x07);
+		break;
+	case 6:
+		dptxwr(it6505, 0xF9, 0x0B);
+		break;
+	case 7:
+		dptxwr(it6505, 0xF9, 0x0F);
+		break;
+	case 8:
+		dptxwr(it6505, 0xF9, 0x1F);
+		break;
+	default:
+		DRM_DEV_ERROR(dev, "audio channel number error: %u",
+			      it6505->aud_ch);
+	}
+	/* Enable Audio InfoFrame */
+	dptxset(it6505, 0xE8, 0x22, 0x22);
+}
+
+static void it6505_set_audio(struct it6505 *it6505)
+{
+	struct device *dev = &it6505->client->dev;
+	unsigned int regbe;
+
+	/* Audio Clock Domain Reset */
+	dptxset(it6505, 0x05, 0x02, 0x02);
+	/* Audio mute */
+	dptxset(it6505, 0xD3, 0x20, 0x20);
+	/* Release Audio Clock Domain Reset */
+	dptxset(it6505, 0x05, 0x02, 0x00);
+
+	dptxrd(it6505, 0xBE, &regbe);
+	if (regbe == 0xFF)
+		DRM_DEV_DEBUG_DRIVER(dev, "no audio input");
+	else
+		DRM_DEV_DEBUG_DRIVER(dev, "audio input fs: %d.%d kHz",
+				     6750 / regbe, 67500 % regbe);
+	dptx_set_aud_fmt(it6505);
+	dptx_set_aud_chsts(it6505);
+	dptx_set_audio_infoframe(it6505);
+
+	/* Enable Enhanced Audio TimeStmp Mode */
+	dptxset(it6505, 0xD4, 0x04, 0x04);
+	/* Disable Full Audio Packet */
+	dptxset(it6505, 0xBB, 0x10, 0x00);
+
+	dptxwr(it6505, 0xDE, 0x00);
+	dptxwr(it6505, 0xDF, 0x80);
+	dptxwr(it6505, 0xE0, 0x00);
+	dptxset(it6505, 0xB8, 0x80, 0x80);
+	dptxset(it6505, 0xB8, 0x80, 0x00);
+	dptxset(it6505, 0xD3, 0x20, 0x00);
+}
+
+/***************************************************************************
+ * DPCD Read and EDID
+ ***************************************************************************/
+
+static unsigned int dptx_dpcdrd(struct it6505 *it6505, unsigned long offset)
+{
+	u8 value;
+	int ret;
+	struct device *dev = &it6505->client->dev;
+
+	ret = drm_dp_dpcd_readb(&it6505->aux, offset, &value);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "DPCD read failed [0x%lx] ret: %d", offset,
+			      ret);
+		return 0;
+	}
+	return value;
+}
+
+static int dptx_dpcdwr(struct it6505 *it6505, unsigned long offset,
+		       unsigned long datain)
+{
+	int ret;
+	struct device *dev = &it6505->client->dev;
+
+	ret = drm_dp_dpcd_writeb(&it6505->aux, offset, datain);
+	if (ret < 0) {
+		DRM_DEV_ERROR(dev, "DPCD write failed [0x%lx] ret: %d", offset,
+			      ret);
+		return ret;
+	}
+	return 0;
+}
+
+static int it6505_get_dpcd(struct it6505 *it6505, int offset, u8 *dpcd, int num)
+{
+	int i, ret;
+	struct device *dev = &it6505->client->dev;
+
+	for (i = 0; i < num; i += 4) {
+		ret = drm_dp_dpcd_read(&it6505->aux, offset + i, dpcd + i,
+				       min(num - i, 4));
+		if (ret < 0)
+			return ret;
+	}
+
+	DRM_DEV_DEBUG_DRIVER(dev, "DPCD[0x%x] = %*ph", offset, num, dpcd);
+	return 0;
+}
+
+static void it6505_parse_dpcd(struct it6505 *it6505)
+{
+	u8 dpcd[DP_RECEIVER_CAP_SIZE];
+	struct device *dev = &it6505->client->dev;
+	int bcaps;
+	struct drm_dp_link *link = &it6505->link;
+
+	drm_dp_link_probe(&it6505->aux, link);
+	it6505_get_dpcd(it6505, DP_DPCD_REV, dpcd, ARRAY_SIZE(dpcd));
+
+	DRM_DEV_DEBUG_DRIVER(dev, "#########DPCD Rev.: %d.%d###########",
+			     link->revision >> 4, link->revision & 0x0F);
+
+	switch (link->rate) {
+	case 162000:
+		DRM_DEV_DEBUG_DRIVER(dev,
+				     "Maximum Link Rate: 1.62Gbps per lane");
+		if (it6505->hbr) {
+			DRM_DEV_DEBUG_DRIVER(
+				dev, "Not support HBR Mode, will train LBR");
+			it6505->hbr = false;
+		} else {
+			DRM_DEV_DEBUG_DRIVER(dev, "Training LBR");
+		}
+		break;
+
+	case 270000:
+		DRM_DEV_DEBUG_DRIVER(dev,
+				     "Maximum Link Rate: 2.7Gbps per lane");
+		if (!it6505->hbr) {
+			DRM_DEV_DEBUG_DRIVER(
+				dev, "Support HBR Mode, will train LBR");
+			it6505->hbr = false;
+		} else {
+			DRM_DEV_DEBUG_DRIVER(dev, "Training HBR");
+		}
+		break;
+
+	case 540000:
+		/* TODO(pihsun): Check if this is correct. HBR here? */
+		DRM_DEV_DEBUG_DRIVER(dev,
+				     "Maximum Link Rate: 2.7Gbps per lane");
+		break;
+
+	default:
+		DRM_DEV_ERROR(dev, "Unknown Maximum Link Rate: %u",
+			      link->rate);
+		break;
+	}
+
+	if (link->num_lanes == 1 || link->num_lanes == 2 ||
+	    link->num_lanes == 4) {
+		DRM_DEV_DEBUG_DRIVER(
+			dev, "Lane Count: %u lane", link->num_lanes);
+		if (link->num_lanes > LANE)
+			link->num_lanes = LANE;
+		DRM_DEV_DEBUG_DRIVER(dev, "Training %u lane", link->num_lanes);
+	} else {
+		DRM_DEV_ERROR(dev, "Lane Count Error: %u", link->num_lanes);
+	}
+
+	if (link->capabilities & DP_LINK_CAP_ENHANCED_FRAMING)
+		DRM_DEV_DEBUG_DRIVER(dev, "Support Enhanced Framing");
+	else
+		DRM_DEV_DEBUG_DRIVER(dev,
+				     "Can not support Enhanced Framing Mode");
+
+	if (dpcd[DP_MAX_DOWNSPREAD] & DP_MAX_DOWNSPREAD_0_5) {
+		DRM_DEV_DEBUG_DRIVER(dev,
+				     "Maximum Down-Spread: 0.5, support SSC!");
+	} else {
+		DRM_DEV_DEBUG_DRIVER(dev,
+				     "Maximum Down-Spread: 0, No support SSC!");
+		it6505->en_ssc = 0;
+	}
+
+	if (link->revision >= 0x11 &&
+	    dpcd[DP_MAX_DOWNSPREAD] & DP_NO_AUX_HANDSHAKE_LINK_TRAINING)
+		DRM_DEV_DEBUG_DRIVER(dev, "Support No AUX Training");
+	else
+		DRM_DEV_DEBUG_DRIVER(dev, "Can not support No AUX Training");
+
+	bcaps = dptx_dpcdrd(it6505, DP_AUX_HDCP_BCAPS);
+	if (bcaps & DP_BCAPS_HDCP_CAPABLE) {
+		DRM_DEV_DEBUG_DRIVER(dev, "Sink support HDCP!");
+		it6505->cp_capable = true;
+	} else {
+		DRM_DEV_DEBUG_DRIVER(dev, "Sink not support HDCP!");
+		it6505->cp_capable = false;
+		it6505->en_hdcp = 0;
+	}
+
+	if (bcaps & DP_BCAPS_REPEATER_PRESENT) {
+		DRM_DEV_DEBUG_DRIVER(dev, "Downstream is repeater!!");
+		it6505->downstream_repeater = true;
+	} else {
+		DRM_DEV_DEBUG_DRIVER(dev, "Downstream is receiver!!");
+		it6505->downstream_repeater = false;
+	}
+}
+
+static void it6505_enable_hdcp(struct it6505 *it6505)
+{
+	u8 bksvs[5], c;
+	struct device *dev = &it6505->client->dev;
+
+	/* Disable CP_Desired */
+	dptxset(it6505, 0x38, 0x0B, 0x00);
+	dptxset(it6505, 0x05, 0x10, 0x10);
+
+	usleep_range(1000, 1500);
+	c = dptx_dpcdrd(it6505, DP_AUX_HDCP_BCAPS);
+	DRM_DEV_DEBUG_DRIVER(dev, "DPCD[0x68028]: 0x%x\n", c);
+	if (!c)
+		return;
+
+	dptxset(it6505, 0x05, 0x10, 0x00);
+	/* Disable CP_Desired */
+	dptxset(it6505, 0x38, 0x01, 0x00);
+	/* Use R0' 100ms waiting */
+	dptxset(it6505, 0x38, 0x08, 0x00);
+	/* clear the repeater List Chk Done and fail bit */
+	dptxset(it6505, 0x39, 0x30, 0x00);
+
+	it6505_get_dpcd(it6505, DP_AUX_HDCP_BKSV, bksvs, ARRAY_SIZE(bksvs));
+
+	DRM_DEV_DEBUG_DRIVER(dev, "Sink BKSV = %5ph", bksvs);
+
+	/* Select An Generator */
+	dptxset(it6505, 0x3A, 0x01, 0x01);
+	/* Enable An Generator */
+	dptxset(it6505, 0x3A, 0x02, 0x02);
+	/* delay1ms(10);*/
+	usleep_range(10000, 15000);
+	/* Stop An Generator */
+	dptxset(it6505, 0x3A, 0x02, 0x00);
+
+	dptxset(it6505, 0x38, 0x01, 0x01);
+	dptxset(it6505, 0x39, 0x01, 0x01);
+}
+
+static void it6505_lanespeed_setup(struct it6505 *it6505)
+{
+	if (!it6505->hbr) {
+		dptxset(it6505, 0x16, 0x01, 0x01);
+		dptxset(it6505, 0x5C, 0x02, 0x00);
+	} else {
+		dptxset(it6505, 0x16, 0x01, 0x00);
+		dptxset(it6505, 0x5C, 0x02, 0x02);
+	}
+}
+
+static void it6505_lane_swap(struct it6505 *it6505)
+{
+	int err;
+	union extcon_property_value property;
+	struct device *dev = &it6505->client->dev;
+
+	if (!it6505->laneswap_disabled) {
+		err = extcon_get_property(it6505->extcon, EXTCON_DISP_DP,
+					  EXTCON_PROP_USB_TYPEC_POLARITY,
+					  &property);
+		if (err) {
+			DRM_DEV_ERROR(dev, "get property fail!");
+			return;
+		}
+		it6505->laneswap = property.intval;
+	}
+
+	dptxset(it6505, 0x16, 0x08, it6505->laneswap ? 0x08 : 0x00);
+	dptxset(it6505, 0x16, 0x06, (it6505->link.num_lanes - 1) << 1);
+	DRM_DEV_DEBUG_DRIVER(dev, "it6505->laneswap = 0x%x", it6505->laneswap);
+
+	if (it6505->laneswap) {
+		switch (it6505->link.num_lanes) {
+		case 1:
+			dptxset(it6505, 0x5C, 0xF1, 0x81);
+			break;
+		case 2:
+			dptxset(it6505, 0x5C, 0xF1, 0xC1);
+			break;
+		default:
+			dptxset(it6505, 0x5C, 0xF1, 0xF1);
+			break;
+		}
+	} else {
+		switch (it6505->link.num_lanes) {
+		case 1:
+			dptxset(it6505, 0x5C, 0xF1, 0x11);
+			break;
+		case 2:
+			dptxset(it6505, 0x5C, 0xF1, 0x31);
+			break;
+		default:
+			dptxset(it6505, 0x5C, 0xF1, 0xF1);
+			break;
+		}
+	}
+}
+
+static void it6505_lane_config(struct it6505 *it6505)
+{
+	it6505_lanespeed_setup(it6505);
+	it6505_lane_swap(it6505);
+}
+
+static void it6505_set_ssc(struct it6505 *it6505)
+{
+	struct device *dev = &it6505->client->dev;
+
+	dptxset(it6505, 0x16, 0x10, it6505->en_ssc << 4);
+	if (it6505->en_ssc) {
+		DRM_DEV_DEBUG_DRIVER(dev, "Enable 27M 4463 PPM SSC");
+		dptx_chgbank(it6505, 1);
+		dptxwr(it6505, 0x88, 0x9e);
+		dptxwr(it6505, 0x89, 0x1c);
+		dptxwr(it6505, 0x8A, 0x42);
+		dptx_chgbank(it6505, 0);
+		dptxwr(it6505, 0x58, 0x07);
+		dptxwr(it6505, 0x59, 0x29);
+		dptxwr(it6505, 0x5A, 0x03);
+		/* Stamp Interrupt Step */
+		dptxset(it6505, 0xD4, 0x30, 0x10);
+		dptx_dpcdwr(it6505, DP_DOWNSPREAD_CTRL, DP_SPREAD_AMP_0_5);
+	} else {
+		dptx_dpcdwr(it6505, DP_DOWNSPREAD_CTRL, 0x00);
+		dptxset(it6505, 0xD4, 0x30, 0x00);
+	}
+}
+
+static void pclk_phase(struct it6505 *it6505)
+{
+	dptxset(it6505, 0x10, 0x03, PCLK_DELAY);
+	dptxset(it6505, 0x12, 0x10, PCLK_INV << 4);
+}
+
+static void afe_driving_setting(struct it6505 *it6505)
+{
+	struct device *dev = &it6505->client->dev;
+	unsigned int afe_setting;
+
+	afe_setting = AFE_SETTING;
+	if (afe_setting >= ARRAY_SIZE(afe_setting_table)) {
+		DRM_DEV_ERROR(dev, "afe setting value error and use default");
+		afe_setting = 0;
+	}
+	if (afe_setting) {
+		dptx_chgbank(it6505, 1);
+		dptxwr(it6505, 0x7E, afe_setting_table[afe_setting][0]);
+		dptxwr(it6505, 0x7F, afe_setting_table[afe_setting][1]);
+		dptxwr(it6505, 0x81, afe_setting_table[afe_setting][2]);
+		dptx_chgbank(it6505, 0);
+	}
+}
+
+static void dptx_output(struct it6505 *it6505)
+{
+	/* change bank 0 */
+	dptx_chgbank(it6505, 0);
+	dptxwr(it6505, 0x64, 0x10);
+	dptxwr(it6505, 0x65, 0x80);
+	dptxwr(it6505, 0x66, 0x10);
+	dptxwr(it6505, 0x67, 0x4F);
+	dptxwr(it6505, 0x68, 0x09);
+	dptxwr(it6505, 0x69, 0xBA);
+	dptxwr(it6505, 0x6A, 0x3B);
+	dptxwr(it6505, 0x6B, 0x4B);
+	dptxwr(it6505, 0x6C, 0x3E);
+	dptxwr(it6505, 0x6D, 0x4F);
+	dptxwr(it6505, 0x6E, 0x09);
+	dptxwr(it6505, 0x6F, 0x56);
+	dptxwr(it6505, 0x70, 0x0E);
+	dptxwr(it6505, 0x71, 0x00);
+	dptxwr(it6505, 0x72, 0x00);
+	dptxwr(it6505, 0x73, 0x4F);
+	dptxwr(it6505, 0x74, 0x09);
+	dptxwr(it6505, 0x75, 0x00);
+	dptxwr(it6505, 0x76, 0x00);
+	dptxwr(it6505, 0x77, 0xE7);
+	dptxwr(it6505, 0x78, 0x10);
+	dptxwr(it6505, 0xE8, 0x00);
+	dptxset(it6505, 0xCE, 0x70, 0x60);
+	dptxwr(it6505, 0xCA, 0x4D);
+	dptxwr(it6505, 0xC9, 0xF5);
+	dptxwr(it6505, 0x5C, 0x02);
+
+	drm_dp_link_power_up(&it6505->aux, &it6505->link);
+	dptxset(it6505, 0x59, 0x01, 0x01);
+	dptxset(it6505, 0x5A, 0x05, 0x01);
+	dptxwr(it6505, 0x12, 0x01);
+	dptxwr(it6505, 0xCB, 0x17);
+	dptxwr(it6505, 0x11, 0x09);
+	dptxwr(it6505, 0x20, 0x28);
+	dptxset(it6505, 0x23, 0x30, 0x00);
+	dptxset(it6505, 0x3A, 0x04, 0x04);
+	dptxset(it6505, 0x15, 0x01, 0x01);
+	dptxwr(it6505, 0x0C, 0x08);
+
+	dptxset(it6505, 0x5F, 0x20, 0x00);
+	it6505_lane_config(it6505);
+
+	it6505_set_ssc(it6505);
+
+	if (it6505->link.capabilities & DP_LINK_CAP_ENHANCED_FRAMING) {
+		dptxwr(it6505, 0xD3, 0x33);
+		dptx_dpcdwr(it6505, DP_LANE_COUNT_SET,
+			    DP_LANE_COUNT_ENHANCED_FRAME_EN);
+	} else {
+		dptxwr(it6505, 0xD3, 0x32);
+	}
+
+	dptxset(it6505, 0x15, 0x02, 0x02);
+	dptxset(it6505, 0x15, 0x02, 0x00);
+	dptxset(it6505, 0x05, 0x03, 0x02);
+	dptxset(it6505, 0x05, 0x03, 0x00);
+
+	/* reg60[2] = InDDR */
+	dptxwr(it6505, 0x60, 0x44);
+	/* M444B24 format */
+	dptxwr(it6505, 0x62, 0x01);
+	/* select RGB Bypass CSC */
+	dptxwr(it6505, 0x63, 0x00);
+
+	pclk_phase(it6505);
+	dptxset(it6505, 0x61, 0x01, 0x01);
+	dptxwr(it6505, 0x06, 0xFF);
+	dptxwr(it6505, 0x07, 0xFF);
+	dptxwr(it6505, 0x08, 0xFF);
+
+	dptxset(it6505, 0xd3, 0x30, 0x00);
+	dptxset(it6505, 0xd4, 0x41, 0x41);
+	dptxset(it6505, 0xe8, 0x11, 0x11);
+
+	afe_driving_setting(it6505);
+	dptxwr(it6505, 0x17, 0x04);
+	dptxwr(it6505, 0x17, 0x01);
+}
+
+static void dptx_process_sys_wait(struct it6505 *it6505)
+{
+	int reg0e;
+	struct device *dev = &it6505->client->dev;
+
+	dptxrd(it6505, 0x0E, &reg0e);
+	DRM_DEV_DEBUG_DRIVER(dev, "SYS_WAIT state reg0e=0x%02x", reg0e);
+
+	if (reg0e & BIT(4)) {
+		DRM_DEV_DEBUG_DRIVER(dev, "Auto Link Training Success...");
+		DRM_DEV_DEBUG_DRIVER(dev, "Link State: 0x%x", reg0e & 0x1F);
+		if (it6505->en_audio) {
+			DRM_DEV_DEBUG_DRIVER(dev, "Enable audio!");
+			it6505_set_audio(it6505);
+		}
+		DRM_DEV_DEBUG_DRIVER(dev, "it6505->VidStable_Done = %02x",
+				     it6505->vidstable_done);
+		if (it6505->cp_capable) {
+			DRM_DEV_DEBUG_DRIVER(dev, "Support HDCP");
+			if (it6505->en_hdcp) {
+				DRM_DEV_DEBUG_DRIVER(dev, "Enable HDCP");
+				dptx_sys_chg(it6505, SYS_ReHDCP);
+			} else {
+				DRM_DEV_DEBUG_DRIVER(dev, "Disable HDCP");
+				dptx_sys_chg(it6505, SYS_NOROP);
+			}
+		} else {
+			DRM_DEV_DEBUG_DRIVER(dev, "Not support HDCP");
+			dptx_sys_chg(it6505, SYS_NOROP);
+		}
+	} else {
+		DRM_DEV_DEBUG_DRIVER(dev, "Auto Link Training fail step %d",
+				     it6505->cntfsm);
+		dptx_debug_print(it6505, 0x0D, "system status");
+		if (it6505->cntfsm > 0) {
+			it6505->cntfsm--;
+			dptx_sys_chg(it6505, SYS_AUTOTRAIN);
+		} else {
+			DRM_DEV_DEBUG_DRIVER(dev, "Auto Training Fail %d times",
+					     TRAINFAILCNT);
+			DRM_DEV_DEBUG_DRIVER(dev, "Sys change to SYS_HPD");
+			dptx_dpcdwr(it6505, DP_TRAINING_PATTERN_SET, 0x00);
+			if (it6505->train_fail_hpd > 0) {
+				it6505->train_fail_hpd--;
+				dptx_sys_chg(it6505, SYS_HPD);
+			} else {
+				dptx_sys_chg(it6505, SYS_TRAINFAIL);
+			}
+		}
+	}
+}
+
+static void dptx_sys_fsm(struct it6505 *it6505)
+{
+	unsigned int i;
+	int reg0e;
+	struct device *dev = &it6505->client->dev;
+
+	if (it6505->status != SYS_UNPLUG && !dptx_getsinkhpd(it6505))
+		dptx_sys_chg(it6505, SYS_UNPLUG);
+
+	DRM_DEV_DEBUG_DRIVER(dev, "state: %s", state_string[it6505->status]);
+	switch (it6505->status) {
+	case SYS_UNPLUG:
+		drm_helper_hpd_irq_event(it6505->connector.dev);
+		break;
+
+	case SYS_HPD:
+		dptx_debug_print(it6505, 0x9F, "aux status");
+		drm_helper_hpd_irq_event(it6505->connector.dev);
+		it6505_init_fsm(it6505);
+		/* GETDPCD */
+		it6505_parse_dpcd(it6505);
+
+		/*
+		 * training fail TRAINFAILCNT times,
+		 * then change to HPD to restart
+		 */
+		it6505->cntfsm = TRAINFAILCNT;
+		DRM_DEV_DEBUG_DRIVER(dev, "will Train %s %d lanes",
+				     it6505->hbr ? "HBR" : "LBR",
+				     it6505->link.num_lanes);
+		dptx_sys_chg(it6505, SYS_AUTOTRAIN);
+		break;
+
+	case SYS_AUTOTRAIN:
+		dptx_output(it6505);
+
+		/*
+		 * waiting for training down flag
+		 * because we don't know
+		 * how long this step will be completed
+		 * so use step 1ms to wait
+		 */
+		for (i = 0; i < FLAGTRAINDOWN; i++) {
+			usleep_range(1000, 2000);
+			dptxrd(it6505, 0x0E, &reg0e);
+			if (reg0e & BIT(4))
+				break;
+		}
+
+		dptx_sys_chg(it6505, SYS_WAIT);
+		break;
+
+	case SYS_WAIT:
+		dptx_process_sys_wait(it6505);
+		break;
+
+	case SYS_ReHDCP:
+		msleep(2400);
+		dptx_debug_print(it6505, 0x3B, "ar0_low");
+		dptx_debug_print(it6505, 0x3C, "ar0_high");
+		dptx_debug_print(it6505, 0x45, "br0_low");
+		dptx_debug_print(it6505, 0x46, "br0_high");
+		it6505_enable_hdcp(it6505);
+		DRM_DEV_DEBUG_DRIVER(dev, "SYS_ReHDCP end");
+		break;
+
+	case SYS_NOROP:
+		break;
+
+	case SYS_TRAINFAIL:
+		break;
+
+	default:
+		DRM_DEV_ERROR(dev, "sys_state change to unknown_state: %d",
+			      it6505->status);
+		break;
+	}
+}
+
+static int sha1_digest(struct it6505 *it6505, u8 *sha1_input, unsigned int size,
+		       u8 *output_av)
+{
+	struct shash_desc *desc;
+	struct crypto_shash *tfm;
+	int err;
+	struct device *dev = &it6505->client->dev;
+
+	tfm = crypto_alloc_shash("sha1", 0, 0);
+	if (IS_ERR(tfm)) {
+		DRM_DEV_ERROR(dev, "crypto_alloc_shash sha1 failed");
+		return PTR_ERR(tfm);
+	}
+	desc = kzalloc(sizeof(*desc) + crypto_shash_descsize(tfm), GFP_KERNEL);
+	if (!desc) {
+		crypto_free_shash(tfm);
+		return -ENOMEM;
+	}
+
+	desc->tfm = tfm;
+	err = crypto_shash_digest(desc, sha1_input, size, output_av);
+	if (err)
+		DRM_DEV_ERROR(dev, "crypto_shash_digest sha1 failed");
+
+	crypto_free_shash(tfm);
+	kfree(desc);
+	return err;
+}
+
+static int it6505_makeup_sha1_input(struct it6505 *it6505)
+{
+	int msgcnt = 0, i;
+	unsigned int value;
+	u8 am0[8], binfo[2];
+	struct device *dev = &it6505->client->dev;
+
+	dptxset(it6505, 0x3A, 0x20, 0x20);
+	for (i = 0; i < 8; i++) {
+		dptxrd(it6505, 0x4C + i, &value);
+		am0[i] = value;
+	}
+	DRM_DEV_DEBUG_DRIVER(dev, "read am0 = %8ph", am0);
+	dptxset(it6505, 0x3A, 0x20, 0x00);
+
+	it6505_get_dpcd(it6505, DP_AUX_HDCP_BINFO, binfo, ARRAY_SIZE(binfo));
+	DRM_DEV_DEBUG_DRIVER(dev, "Attached devices: %02x", binfo[0] & 0x7F);
+
+	DRM_DEV_DEBUG_DRIVER(dev, "%s 127 devices are attached",
+			     (binfo[0] & BIT(7)) ? "over" : "under");
+	DRM_DEV_DEBUG_DRIVER(dev, "depth, attached levels: %02x",
+			     binfo[1] & 0x07);
+	DRM_DEV_DEBUG_DRIVER(dev, "%s than seven levels cascaded",
+			     (binfo[1] & BIT(3)) ? "more" : "less");
+
+	for (i = 0; i < (binfo[0] & 0x7F); i++) {
+		it6505_get_dpcd(it6505, DP_AUX_HDCP_KSV_FIFO + (i % 3) * 5,
+				it6505->shainput + msgcnt, 5);
+		msgcnt += 5;
+
+		DRM_DEV_DEBUG_DRIVER(dev, "KSV List %d device : %5ph", i,
+				     it6505->shainput + i * 5);
+	}
+	it6505->shainput[msgcnt++] = binfo[0];
+	it6505->shainput[msgcnt++] = binfo[1];
+	for (i = 0; i < 8; i++)
+		it6505->shainput[msgcnt++] = am0[i];
+
+	DRM_DEV_DEBUG_DRIVER(dev, "SHA Message Count = %d", msgcnt);
+	return msgcnt;
+}
+
+static void it6505_check_sha1_result(struct it6505 *it6505)
+{
+	unsigned int i, shapass;
+	struct device *dev = &it6505->client->dev;
+
+	DRM_DEV_DEBUG_DRIVER(dev, "SHA calculate complete");
+	for (i = 0; i < 5; i++)
+		DRM_DEV_DEBUG_DRIVER(dev, "av %d: %4ph", i, it6505->av[i]);
+
+	shapass = 1;
+	for (i = 0; i < 5; i++) {
+		it6505_get_dpcd(it6505, DP_AUX_HDCP_V_PRIME(i), it6505->bv[i],
+				4);
+		DRM_DEV_DEBUG_DRIVER(dev, "bv %d: %4ph", i, it6505->bv[i]);
+		if ((it6505->bv[i][3] != it6505->av[i][0]) ||
+		    (it6505->bv[i][2] != it6505->av[i][1]) ||
+		    (it6505->bv[i][1] != it6505->av[i][2]) ||
+		    (it6505->bv[i][0] != it6505->av[i][3])) {
+			shapass = 0;
+		}
+	}
+	if (shapass) {
+		DRM_DEV_DEBUG_DRIVER(dev, "SHA check result pass!");
+		dptxset(it6505, 0x39, BIT(4), BIT(4));
+	} else {
+		DRM_DEV_DEBUG_DRIVER(dev, "SHA check result fail");
+		dptxset(it6505, 0x39, BIT(5), BIT(5));
+	}
+}
+
+static void to_fsm_status(struct it6505 *it6505, enum sys_status status)
+{
+	while (it6505->status != status && it6505->status != SYS_TRAINFAIL) {
+		dptx_sys_fsm(it6505);
+		if (it6505->status == SYS_UNPLUG)
+			return;
+	}
+}
+
+static void go_on_fsm(struct it6505 *it6505);
+
+static u8 dp_link_status(const u8 link_status[DP_LINK_STATUS_SIZE], int r)
+{
+	return link_status[r - DP_LANE0_1_STATUS];
+}
+
+static void hpd_irq(struct it6505 *it6505)
+{
+	u8 dpcd_sink_count, dpcd_irq_vector;
+	u8 link_status[DP_LINK_STATUS_SIZE];
+	unsigned int bstatus;
+	struct device *dev = &it6505->client->dev;
+
+	dpcd_sink_count = dptx_dpcdrd(it6505, DP_SINK_COUNT);
+	dpcd_irq_vector = dptx_dpcdrd(it6505, DP_DEVICE_SERVICE_IRQ_VECTOR);
+	drm_dp_dpcd_read_link_status(&it6505->aux, link_status);
+
+	DRM_DEV_DEBUG_DRIVER(dev, "dpcd_sink_count = 0x%x", dpcd_sink_count);
+	DRM_DEV_DEBUG_DRIVER(dev, "dpcd_irq_vector = 0x%x", dpcd_irq_vector);
+	DRM_DEV_DEBUG_DRIVER(dev, "link_status = %*ph",
+			     (int)ARRAY_SIZE(link_status), link_status);
+
+	if (dpcd_irq_vector & DP_CP_IRQ) {
+		bstatus = dptx_dpcdrd(it6505, DP_AUX_HDCP_BSTATUS);
+		dptxset(it6505, 0x39, 0x02, 0x02);
+		DRM_DEV_DEBUG_DRIVER(dev, "Receive CP_IRQ, bstatus = 0x%02x",
+				     bstatus);
+		dptx_debug_print(it6505, 0x55, "");
+
+		if (bstatus & DP_BSTATUS_READY)
+			DRM_DEV_DEBUG_DRIVER(dev, "HDCP KSV list ready");
+
+		if (bstatus & DP_BSTATUS_LINK_FAILURE) {
+			DRM_DEV_DEBUG_DRIVER(
+				dev, "Link Integrity Fail, restart HDCP");
+			return;
+		}
+		if (bstatus & DP_BSTATUS_R0_PRIME_READY)
+			DRM_DEV_DEBUG_DRIVER(dev, "HDCP R0' ready");
+	}
+
+	if (dp_link_status(link_status, DP_LANE_ALIGN_STATUS_UPDATED) &
+	    DP_LINK_STATUS_UPDATED) {
+		if (!drm_dp_channel_eq_ok(link_status,
+					  it6505->link.num_lanes)) {
+			DRM_DEV_DEBUG_DRIVER(dev, "Link Re-Training");
+			dptxset(it6505, 0xD3, 0x30, 0x30);
+			dptxset(it6505, 0xE8, 0x33, 0x00);
+			msleep(500);
+			dptx_sys_chg(it6505, SYS_HPD);
+			go_on_fsm(it6505);
+		}
+	}
+}
+
+static void go_on_fsm(struct it6505 *it6505)
+{
+	struct device *dev = &it6505->client->dev;
+
+	if (it6505->cp_capable) {
+		DRM_DEV_DEBUG_DRIVER(dev, "Support HDCP, cp_capable: %d",
+				     it6505->cp_capable);
+		if (it6505->en_hdcp) {
+			DRM_DEV_DEBUG_DRIVER(dev, "Enable HDCP");
+			to_fsm_status(it6505, SYS_ReHDCP);
+			dptx_sys_fsm(it6505);
+
+		} else {
+			DRM_DEV_DEBUG_DRIVER(dev, "Disable HDCP");
+			to_fsm_status(it6505, SYS_NOROP);
+		}
+	} else {
+		DRM_DEV_DEBUG_DRIVER(dev, "Not support HDCP");
+		to_fsm_status(it6505, SYS_NOROP);
+	}
+}
+
+static void it6505_check_reg06(struct it6505 *it6505, unsigned int reg06)
+{
+	unsigned int rddata;
+	struct device *dev = &it6505->client->dev;
+
+	if (reg06 & BIT(0)) {
+		/* hpd pin status change */
+		DRM_DEV_DEBUG_DRIVER(dev, "HPD Change Interrupt");
+		if (dptx_getsinkhpd(it6505)) {
+			dptx_sys_chg(it6505, SYS_HPD);
+			dptx_sys_fsm(it6505);
+			dptxrd(it6505, 0x0D, &rddata);
+			if (rddata & BIT(2)) {
+				go_on_fsm(it6505);
+			} else {
+				dptxwr(it6505, 0x05, 0x00);
+				dptxset(it6505, 0x61, 0x02, 0x02);
+				dptxset(it6505, 0x61, 0x02, 0x00);
+			}
+		} else {
+			dptx_sys_chg(it6505, SYS_UNPLUG);
+			dptx_sys_fsm(it6505);
+			return;
+		}
+	}
+
+	if (it6505->cp_capable) {
+		if (reg06 & BIT(4)) {
+			DRM_DEV_DEBUG_DRIVER(dev,
+					     "HDCP encryption Done Interrupt");
+			it6505->cp_done = 1;
+			dptx_sys_chg(it6505, SYS_NOROP);
+		}
+
+		if (reg06 & BIT(3)) {
+			DRM_DEV_DEBUG_DRIVER(
+				dev, "HDCP encryption Fail Interrupt, retry");
+			it6505->cp_done = 0;
+			it6505_init_and_mask_on(it6505);
+		}
+	}
+
+	if (reg06 & BIT(1)) {
+		DRM_DEV_DEBUG_DRIVER(dev, "HPD IRQ Interrupt");
+		hpd_irq(it6505);
+	}
+
+	if (reg06 & BIT(2)) {
+		dptxrd(it6505, 0x0D, &rddata);
+
+		if (rddata & BIT(2)) {
+			DRM_DEV_DEBUG_DRIVER(dev, "Video Stable On Interrupt");
+			it6505->vidstable_done = 1;
+			dptx_sys_chg(it6505, SYS_AUTOTRAIN);
+			go_on_fsm(it6505);
+		} else {
+			DRM_DEV_DEBUG_DRIVER(dev, "Video Stable Off Interrupt");
+			it6505->vidstable_done = 0;
+		}
+	}
+}
+
+static void it6505_check_reg07(struct it6505 *it6505, unsigned int reg07)
+{
+	struct device *dev = &it6505->client->dev;
+	unsigned int len, i;
+	unsigned int bstatus;
+
+	if (it6505->status == SYS_UNPLUG)
+		return;
+	if (reg07 & BIT(0))
+		DRM_DEV_DEBUG_DRIVER(dev, "AUX PC Request Fail Interrupt");
+
+	if (reg07 & BIT(1)) {
+		DRM_DEV_DEBUG_DRIVER(dev, "HDCP event Interrupt");
+		for (i = 0; i < POLLINGKSVLIST; i++) {
+			bstatus = dptx_dpcdrd(it6505, DP_AUX_HDCP_BSTATUS);
+			usleep_range(2000, 3000);
+			if (bstatus & DP_BSTATUS_READY)
+				break;
+		}
+
+		/*
+		 * Read Bstatus to determine what happened
+		 */
+		DRM_DEV_DEBUG_DRIVER(dev, "Bstatus: 0x%02x", bstatus);
+		dptx_debug_print(it6505, 0x3B, "ar0_low");
+		dptx_debug_print(it6505, 0x3C, "ar0_high");
+		dptx_debug_print(it6505, 0x45, "br0_low");
+		dptx_debug_print(it6505, 0x46, "br0_high");
+
+		if (bstatus & DP_BSTATUS_READY) {
+			DRM_DEV_DEBUG_DRIVER(dev, "HDCP KSV list ready");
+			len = it6505_makeup_sha1_input(it6505);
+			sha1_digest(it6505, it6505->shainput, len,
+				    (u8 *)it6505->av);
+			it6505_check_sha1_result(it6505);
+		}
+	}
+	if (it6505->en_audio && (reg07 & BIT(2))) {
+		DRM_DEV_DEBUG_DRIVER(dev, "Audio FIFO OverFlow Interrupt");
+		dptx_debug_print(it6505, 0xBE, "");
+		dptxset(it6505, 0xD3, 0x20, 0x20);
+		dptxset(it6505, 0xE8, 0x22, 0x00);
+		dptxset(it6505, 0xB8, 0x80, 0x80);
+		dptxset(it6505, 0xB8, 0x80, 0x00);
+		it6505_set_audio(it6505);
+	}
+	if (it6505->en_audio && (reg07 & BIT(5)))
+		DRM_DEV_DEBUG_DRIVER(dev, "Audio infoframe packet done");
+}
+
+static void it6505_check_reg08(struct it6505 *it6505, unsigned int reg08)
+{
+	struct device *dev = &it6505->client->dev;
+
+	if (it6505->status == SYS_UNPLUG)
+		return;
+	if (it6505->en_audio && (reg08 & BIT(1)))
+		DRM_DEV_DEBUG_DRIVER(dev, "Audio TimeStamp Packet Done!");
+
+	if (it6505->en_audio && (reg08 & BIT(3))) {
+		DRM_DEV_DEBUG_DRIVER(dev, "Audio M Error Interrupt ...");
+		show_aud_mcnt(it6505);
+	}
+	if (reg08 & BIT(4)) {
+		DRM_DEV_DEBUG_DRIVER(dev, "Link Training Fail Interrupt");
+		/* restart training */
+		dptx_sys_chg(it6505, SYS_AUTOTRAIN);
+		go_on_fsm(it6505);
+	}
+
+	if (reg08 & BIT(7)) {
+		DRM_DEV_DEBUG_DRIVER(dev, "IO Latch FIFO OverFlow Interrupt");
+		dptxset(it6505, 0x61, 0x02, 0x02);
+		dptxset(it6505, 0x61, 0x02, 0x00);
+	}
+}
+
+static void it6505_dptx_irq(struct it6505 *it6505)
+{
+	unsigned int reg06, reg07, reg08, reg0d;
+	struct device *dev = &it6505->client->dev;
+
+	dptxrd(it6505, 0x06, &reg06);
+	dptxrd(it6505, 0x07, &reg07);
+	dptxrd(it6505, 0x08, &reg08);
+	dptxrd(it6505, 0x0D, &reg0d);
+
+	dptxwr(it6505, 0x06, reg06);
+	dptxwr(it6505, 0x07, reg07);
+	dptxwr(it6505, 0x08, reg08);
+
+	DRM_DEV_DEBUG_DRIVER(dev, "reg06 = 0x%02x", reg06);
+	DRM_DEV_DEBUG_DRIVER(dev, "reg07 = 0x%02x", reg07);
+	DRM_DEV_DEBUG_DRIVER(dev, "reg08 = 0x%02x", reg08);
+	DRM_DEV_DEBUG_DRIVER(dev, "reg0d = 0x%02x", reg0d);
+
+	if (reg06 != 0)
+		it6505_check_reg06(it6505, reg06);
+
+	if (reg07 != 0)
+		it6505_check_reg07(it6505, reg07);
+
+	if (reg08 != 0)
+		it6505_check_reg08(it6505, reg08);
+}
+
+static void it6505_bridge_enable(struct drm_bridge *bridge)
+{
+	struct it6505 *it6505 = bridge_to_it6505(bridge);
+
+	if (!it6505->drv_hold) {
+		it6505_int_mask_on(it6505);
+		dptx_sys_chg(it6505, SYS_HPD);
+	}
+}
+
+static void it6505_bridge_disable(struct drm_bridge *bridge)
+{
+	struct it6505 *it6505 = bridge_to_it6505(bridge);
+
+	dptx_sys_chg(it6505, SYS_UNPLUG);
+}
+
+static const struct drm_bridge_funcs it6505_bridge_funcs = {
+	.attach = it6505_bridge_attach,
+	.detach = it6505_bridge_detach,
+	.mode_valid = it6505_bridge_mode_valid,
+	.mode_set = it6505_bridge_mode_set,
+	.enable = it6505_bridge_enable,
+	.disable = it6505_bridge_disable,
+};
+
+static void it6505_clear_int(struct it6505 *it6505)
+{
+	dptxwr(it6505, 0x06, 0xFF);
+	dptxwr(it6505, 0x07, 0xFF);
+	dptxwr(it6505, 0x08, 0xFF);
+}
+
+static irqreturn_t it6505_intp_threaded_handler(int unused, void *data)
+{
+	struct it6505 *it6505 = data;
+	struct device *dev = &it6505->client->dev;
+
+	msleep(150);
+	mutex_lock(&it6505->lock);
+
+	if (it6505->drv_hold == 0 && it6505->powered) {
+		DRM_DEV_DEBUG_DRIVER(dev, "into it6505_dptx_irq");
+		it6505_dptx_irq(it6505);
+	}
+
+	mutex_unlock(&it6505->lock);
+	return IRQ_HANDLED;
+}
+
+static int it6505_init_pdata(struct it6505 *it6505)
+{
+	struct it6505_platform_data *pdata = &it6505->pdata;
+	struct device *dev = &it6505->client->dev;
+
+	/* 1.0V digital core power regulator  */
+	pdata->pwr18 = devm_regulator_get(dev, "pwr18");
+	if (IS_ERR(pdata->pwr18)) {
+		DRM_DEV_ERROR(dev, "pwr18 regulator not found");
+		return PTR_ERR(pdata->pwr18);
+	}
+
+	pdata->ovdd = devm_regulator_get(dev, "ovdd");
+	if (IS_ERR(pdata->ovdd)) {
+		DRM_DEV_ERROR(dev, "ovdd regulator not found");
+		return PTR_ERR(pdata->ovdd);
+	}
+
+	/* GPIO for HPD */
+	pdata->gpiod_hpd = devm_gpiod_get(dev, "hpd", GPIOD_IN);
+	if (IS_ERR(pdata->gpiod_hpd))
+		return PTR_ERR(pdata->gpiod_hpd);
+
+	/* GPIO for chip reset */
+	pdata->gpiod_reset = devm_gpiod_get(dev, "reset", GPIOD_OUT_HIGH);
+
+	return PTR_ERR_OR_ZERO(pdata->gpiod_reset);
+}
+
+static ssize_t drv_hold_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", it6505->drv_hold);
+}
+
+static ssize_t drv_hold_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+
+	if (kstrtoint(buf, 10, &it6505->drv_hold) < 0)
+		return -EINVAL;
+
+	if (it6505->drv_hold) {
+		it6505_int_mask_off(it6505);
+	} else {
+		it6505_clear_int(it6505);
+		it6505_int_mask_on(it6505);
+	}
+	return count;
+}
+
+static ssize_t print_timing_show(struct device *dev,
+				 struct device_attribute *attr, char *buf)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+	struct drm_display_mode *vid = &it6505->vid_info;
+	char *str = buf, *end = buf + PAGE_SIZE;
+
+	str += scnprintf(str, end - str, "---video timing---\n");
+	str += scnprintf(str, end - str, "PCLK:%d.%03dMHz\n", vid->clock / 1000,
+			 vid->clock % 1000);
+	str += scnprintf(str, end - str, "HTotal:%d\n", vid->htotal);
+	str += scnprintf(str, end - str, "HActive:%d\n", vid->hdisplay);
+	str += scnprintf(str, end - str, "HFrontPorch:%d\n",
+			 vid->hsync_start - vid->hdisplay);
+	str += scnprintf(str, end - str, "HSyncWidth:%d\n",
+			 vid->hsync_end - vid->hsync_start);
+	str += scnprintf(str, end - str, "HBackPorch:%d\n",
+			 vid->htotal - vid->hsync_end);
+	str += scnprintf(str, end - str, "VTotal:%d\n", vid->vtotal);
+	str += scnprintf(str, end - str, "VActive:%d\n", vid->vdisplay);
+	str += scnprintf(str, end - str, "VFrontPorch:%d\n",
+			 vid->vsync_start - vid->vdisplay);
+	str += scnprintf(str, end - str, "VSyncWidth:%d\n",
+			 vid->vsync_end - vid->vsync_start);
+	str += scnprintf(str, end - str, "VBackPorch:%d\n",
+			 vid->vtotal - vid->vsync_end);
+
+	return str - buf;
+}
+
+static ssize_t sha_debug_show(struct device *dev, struct device_attribute *attr,
+			      char *buf)
+{
+	int i = 0;
+	char *str = buf, *end = buf + PAGE_SIZE;
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+
+	str += scnprintf(str, end - str, "sha input:\n");
+	for (i = 0; i < ARRAY_SIZE(it6505->shainput); i += 16)
+		str += scnprintf(str, end - str, "%16ph\n",
+				 it6505->shainput + i);
+
+	str += scnprintf(str, end - str, "av:\n");
+	for (i = 0; i < ARRAY_SIZE(it6505->av); i++)
+		str += scnprintf(str, end - str, "%4ph\n", it6505->av[i]);
+
+	str += scnprintf(str, end - str, "bv:\n");
+	for (i = 0; i < ARRAY_SIZE(it6505->bv); i++)
+		str += scnprintf(str, end - str, "%4ph\n", it6505->bv[i]);
+
+	return end - str;
+}
+
+static ssize_t en_hdcp_show(struct device *dev, struct device_attribute *attr,
+			    char *buf)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", it6505->en_hdcp);
+}
+
+static ssize_t en_hdcp_store(struct device *dev, struct device_attribute *attr,
+			     const char *buf, size_t count)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+	unsigned int reg3f, hdcp;
+
+	if (kstrtoint(buf, 10, &it6505->en_hdcp) < 0)
+		return -EINVAL;
+
+	if (!it6505->powered || it6505->status == SYS_UNPLUG) {
+		DRM_DEV_DEBUG_DRIVER(dev,
+				     "power down or unplug, can not fire HDCP");
+		return -EINVAL;
+	}
+
+	if (it6505->en_hdcp) {
+		if (it6505->cp_capable) {
+			dptx_sys_chg(it6505, SYS_ReHDCP);
+			dptx_sys_fsm(it6505);
+		} else {
+			DRM_DEV_ERROR(dev, "sink not support HDCP");
+			it6505->cp_done = 0;
+		}
+	} else {
+		dptxset(it6505, 0x05, 0x10, 0x10);
+		dptxset(it6505, 0x05, 0x10, 0x00);
+		dptxrd(it6505, 0x3F, &reg3f);
+		hdcp = (reg3f & BIT(7)) >> 7;
+		DRM_DEV_DEBUG_DRIVER(dev, "%s to disable hdcp",
+				     hdcp ? "failed" : "succeeded");
+		it6505->cp_done = hdcp;
+	}
+	return count;
+}
+
+static ssize_t en_pwronoff_show(struct device *dev,
+				struct device_attribute *attr, char *buf)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", it6505->en_pwronoff);
+}
+
+static ssize_t en_pwronoff_store(struct device *dev,
+				 struct device_attribute *attr, const char *buf,
+				 size_t count)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+
+	if (kstrtoint(buf, 10, &it6505->en_pwronoff) < 0)
+		return -EINVAL;
+	return count;
+}
+
+static ssize_t en_audio_show(struct device *dev, struct device_attribute *attr,
+			     char *buf)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", it6505->en_audio);
+}
+
+static ssize_t en_audio_store(struct device *dev, struct device_attribute *attr,
+			      const char *buf, size_t count)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+
+	if (kstrtoint(buf, 10, &it6505->en_audio) < 0)
+		return -EINVAL;
+	if (!it6505->powered || it6505->status == SYS_UNPLUG) {
+		DRM_DEV_DEBUG_DRIVER(
+			dev, "power down or unplug, can not output audio");
+		return -EINVAL;
+	}
+
+	if (it6505->en_audio) {
+		it6505_set_audio(it6505);
+	} else {
+		dptxset(it6505, 0x05, 0x02, 0x02);
+		dptxset(it6505, 0x05, 0x02, 0x00);
+	}
+	DRM_DEV_DEBUG_DRIVER(dev, "%s audio",
+			     it6505->en_audio ? "Enable" : "Disable");
+	return count;
+}
+
+static ssize_t force_pwronoff_store(struct device *dev,
+				    struct device_attribute *attr,
+				    const char *buf, size_t count)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+	int pwr;
+
+	if (kstrtoint(buf, 10, &pwr) < 0)
+		return -EINVAL;
+	if (pwr)
+		it6505_poweron(it6505);
+	else
+		it6505_poweroff(it6505);
+	return count;
+}
+
+static ssize_t pwr_status_show(struct device *dev,
+			       struct device_attribute *attr, char *buf)
+{
+	struct it6505 *it6505 = dev_get_drvdata(dev);
+
+	return scnprintf(buf, PAGE_SIZE, "%d\n", it6505->powered);
+}
+
+static DEVICE_ATTR_RO(print_timing);
+static DEVICE_ATTR_RO(pwr_status);
+static DEVICE_ATTR_RO(sha_debug);
+static DEVICE_ATTR_WO(force_pwronoff);
+static DEVICE_ATTR_RW(drv_hold);
+static DEVICE_ATTR_RW(en_hdcp);
+static DEVICE_ATTR_RW(en_pwronoff);
+static DEVICE_ATTR_RW(en_audio);
+
+static const struct attribute *it6505_attrs[] = {
+	&dev_attr_drv_hold.attr,
+	&dev_attr_print_timing.attr,
+	&dev_attr_sha_debug.attr,
+	&dev_attr_en_hdcp.attr,
+	&dev_attr_en_pwronoff.attr,
+	&dev_attr_en_audio.attr,
+	&dev_attr_force_pwronoff.attr,
+	&dev_attr_pwr_status.attr,
+	NULL,
+};
+
+static int it6505_i2c_probe(struct i2c_client *client,
+			    const struct i2c_device_id *id)
+{
+	struct it6505 *it6505;
+	struct it6505_platform_data *pdata;
+	struct device *dev = &client->dev;
+	struct extcon_dev *extcon;
+	int err, intp_irq;
+
+	it6505 = devm_kzalloc(&client->dev, sizeof(*it6505), GFP_KERNEL);
+	if (!it6505)
+		return -ENOMEM;
+
+	mutex_init(&it6505->lock);
+	mutex_init(&it6505->mode_lock);
+
+	pdata = &it6505->pdata;
+
+	it6505->bridge.of_node = client->dev.of_node;
+	it6505->client = client;
+	i2c_set_clientdata(client, it6505);
+
+	/* get extcon device from DTS */
+	extcon = extcon_get_edev_by_phandle(dev, 0);
+	if (PTR_ERR(extcon) == -EPROBE_DEFER)
+		return -EPROBE_DEFER;
+	if (IS_ERR(extcon)) {
+		DRM_DEV_ERROR(dev, "can not get extcon device!");
+		return -EINVAL;
+	}
+
+	it6505->extcon = extcon;
+
+	it6505->laneswap_disabled =
+		device_property_read_bool(dev, "no-laneswap");
+
+	err = it6505_init_pdata(it6505);
+	if (err) {
+		DRM_DEV_ERROR(dev, "Failed to initialize pdata: %d", err);
+		return err;
+	}
+
+	it6505->regmap =
+		devm_regmap_init_i2c(client, &it6505_bridge_regmap_config);
+	if (IS_ERR(it6505->regmap)) {
+		DRM_DEV_ERROR(dev, "regmap i2c init failed");
+		return PTR_ERR(it6505->regmap);
+	}
+
+	intp_irq = client->irq;
+
+	if (!intp_irq) {
+		DRM_DEV_ERROR(dev, "Failed to get CABLE_DET and INTP IRQ");
+		return -ENODEV;
+	}
+
+	err = devm_request_threaded_irq(&client->dev, intp_irq, NULL,
+					it6505_intp_threaded_handler,
+					IRQF_TRIGGER_FALLING | IRQF_ONESHOT,
+					"it6505-intp", it6505);
+	if (err) {
+		DRM_DEV_ERROR(dev, "Failed to request INTP threaded IRQ: %d",
+			      err);
+		return err;
+	}
+
+	/* Register aux channel */
+	it6505->aux.name = "DP-AUX";
+	it6505->aux.dev = dev;
+	it6505->aux.transfer = it6505_aux_transfer;
+	err = drm_dp_aux_register(&it6505->aux);
+	if (err < 0) {
+		DRM_DEV_ERROR(dev, "Failed to register aux: %d", err);
+		return err;
+	}
+
+	it6505->en_pwronoff = DEFAULTPWRONOFF;
+	it6505->drv_hold = DEFAULTDRVHOLD;
+	it6505->en_hdcp = DEFAULTHDCP;
+	it6505->en_audio = DEFAULTAUDIO;
+	it6505->powered = 0;
+
+	if (DEFAULTPWRON)
+		it6505_poweron(it6505);
+	err = sysfs_create_files(&client->dev.kobj, it6505_attrs);
+	if (err) {
+		drm_dp_aux_unregister(&it6505->aux);
+		return err;
+	}
+
+	it6505->bridge.funcs = &it6505_bridge_funcs;
+	drm_bridge_add(&it6505->bridge);
+	return 0;
+}
+
+static int it6505_remove(struct i2c_client *client)
+{
+	struct it6505 *it6505 = i2c_get_clientdata(client);
+
+	drm_bridge_remove(&it6505->bridge);
+	sysfs_remove_files(&client->dev.kobj, it6505_attrs);
+	kfree(it6505->edid);
+	it6505->edid = NULL;
+	drm_connector_unregister(&it6505->connector);
+	drm_dp_aux_unregister(&it6505->aux);
+	return 0;
+}
+
+static const struct i2c_device_id it6505_id[] = {
+	{ "it6505", 0 },
+	{ }
+};
+
+MODULE_DEVICE_TABLE(i2c, it6505_id);
+
+static const struct of_device_id it6505_of_match[] = {
+	{ .compatible = "ite,it6505" },
+	{ }
+};
+
+static struct i2c_driver it6505_i2c_driver = {
+	.driver = {
+		.name = "it6505_dptx",
+		.of_match_table = it6505_of_match,
+	},
+	.probe = it6505_i2c_probe,
+	.remove = it6505_remove,
+	.id_table = it6505_id,
+};
+
+module_i2c_driver(it6505_i2c_driver);
+
+MODULE_AUTHOR("Jitao Shi <jitao.shi@mediatek.com>");
+MODULE_DESCRIPTION("IT6505 DisplayPort Transmitter driver");
+MODULE_LICENSE("GPL v2");
-- 
1.9.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v3 0/2] IT6505 cover letter
From: allen @ 2019-09-12  3:32 UTC (permalink / raw)
  Cc: Maxime Ripard,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Jernej Skrabec, Heiko Stuebner, Jau-Chih Tseng, Allen Chen,
	Jonas Karlman, open list, open list:DRM DRIVERS,
	moderated list:ARM/Mediatek SoC support, Laurent Pinchart,
	Pi-Hsun Shih, Shawn Guo, Rob Herring,
	moderated list:ARM/Mediatek SoC support, Icenowy Zheng

The IT6505 is a high-performance DisplayPort 1.1a transmitter, fully compliant with DisplayPort 1.1a, HDCP 1.3 specifications. The IT6505 supports color depth of up to 36 bits (12 bits/color) and ensures robust transmission of high-quality uncompressed video content, along with uncompressed and compressed digital audio content.

This series contains document bindings, Kconfig to control the function enable or not.

Allen Chen (2):
  WIP: dt-bindings: Add binding for IT6505.
  WIP: drm/bridge: add it6505 driver

 .../bindings/display/bridge/ite,it6505.txt         |   28 +
 .../devicetree/bindings/vendor-prefixes.yaml       |    2 +
 drivers/gpu/drm/bridge/Kconfig                     |    7 +
 drivers/gpu/drm/bridge/Makefile                    |    1 +
 drivers/gpu/drm/bridge/ite-it6505.c                | 2531 ++++++++++++++++++++
 5 files changed, 2569 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it6505.txt
 create mode 100644 drivers/gpu/drm/bridge/ite-it6505.c

-- 
1.9.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v3 1/2] dt-bindings: Add binding for IT6505.
From: allen @ 2019-09-12  3:32 UTC (permalink / raw)
  Cc: Mark Rutland,
	open list:OPEN FIRMWARE AND FLATTENED DEVICE TREE BINDINGS,
	Pi-Hsun Shih, Jau-Chih Tseng, David Airlie, Allen Chen,
	open list:DRM DRIVERS, open list, Maxime Ripard, Hans Verkuil,
	Rob Herring, moderated list:ARM/Mediatek SoC support,
	Laurent Pinchart, Daniel Vetter, Matthias Brugger, Icenowy Zheng,
	Shawn Guo, moderated list:ARM/Mediatek SoC support,
	Heiko Stuebner
In-Reply-To: <1568259199-5827-1-git-send-email-allen.chen@ite.com.tw>

From: Allen Chen <allen.chen@ite.com.tw>

Add a DT binding documentation for IT6505.

Signed-off-by: Allen Chen <allen.chen@ite.com.tw>

Signed-off-by: Pi-Hsun Shih <pihsun@chromium.org>

---
cros-ec does not have an associated driver that uses the standard Linux USB-C driver class.
extcon is used to model the Type-C connector.(crbug.com/982932)
---
 .../bindings/display/bridge/ite,it6505.txt         | 28 ++++++++++++++++++++++
 .../devicetree/bindings/vendor-prefixes.yaml       |  2 ++
 2 files changed, 30 insertions(+)
 create mode 100644 Documentation/devicetree/bindings/display/bridge/ite,it6505.txt

diff --git a/Documentation/devicetree/bindings/display/bridge/ite,it6505.txt b/Documentation/devicetree/bindings/display/bridge/ite,it6505.txt
new file mode 100644
index 0000000..72da0c4
--- /dev/null
+++ b/Documentation/devicetree/bindings/display/bridge/ite,it6505.txt
@@ -0,0 +1,28 @@
+iTE it6505 DP bridge bindings
+
+Required properties:
+        - compatible: "ite,it6505"
+        - reg: i2c address of the bridge
+        - ovdd-supply: I/O voltage
+        - pwr18-supply: Core voltage
+        - interrupts: interrupt specifier of INT pin
+        - reset-gpios: gpio specifier of RESET pin
+	- hpd-gpios:
+		Hotplug detect GPIO.
+		Indicates which GPIO should be used for hotplug detection
+	- port@[x]: SoC specific port nodes with endpoint definitions as defined
+		in Documentation/devicetree/bindings/display/mediatek/mediatek,dpi.txt
+
+Example:
+	dp-bridge@5c {
+                compatible = "ite,it6505";
+                interrupts = <152 IRQ_TYPE_EDGE_RISING 152 0>;
+                reg = <0x5c>;
+                pinctrl-names = "default";
+                pinctrl-0 = <&it6505_pins>;
+                ovdd-supply = <&mt6358_vsim1_reg>;
+                pwr18-supply = <&it6505_pp18_reg>;
+                reset-gpios = <&pio 179 1>;
+                hpd-gpios = <&pio 9 0>;
+                extcon = <&usbc_extcon>;
+        };
diff --git a/Documentation/devicetree/bindings/vendor-prefixes.yaml b/Documentation/devicetree/bindings/vendor-prefixes.yaml
index 967e78c..fb3b643 100644
--- a/Documentation/devicetree/bindings/vendor-prefixes.yaml
+++ b/Documentation/devicetree/bindings/vendor-prefixes.yaml
@@ -461,6 +461,8 @@ patternProperties:
     description: Intersil
   "^issi,.*":
     description: Integrated Silicon Solutions Inc.
+  "^ite,.*":
+    description: ITE Tech. Inc.
   "^itead,.*":
     description: ITEAD Intelligent Systems Co.Ltd
   "^iwave,.*":
-- 
1.9.1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* RE: [PATCH v5 1/2] dt-bindings: mailbox: add binding doc for the ARM SMC/HVC mailbox
From: Peng Fan @ 2019-09-12  3:05 UTC (permalink / raw)
  To: Jassi Brar, Andre Przywara
  Cc: mark.rutland@arm.com, devicetree@vger.kernel.org,
	f.fainelli@gmail.com, linux-kernel@vger.kernel.org,
	robh+dt@kernel.org, dl-linux-imx, sudeep.holla@arm.com,
	linux-arm-kernel@lists.infradead.org
In-Reply-To: <CABb+yY1oZxvX+mRNmObAHsGoBfN0F4GO+9PSj06EFaF3DsnstA@mail.gmail.com>

> Subject: Re: [PATCH v5 1/2] dt-bindings: mailbox: add binding doc for the ARM
> SMC/HVC mailbox
> 
> On Wed, Sep 11, 2019 at 10:03 AM Andre Przywara
> <andre.przywara@arm.com> wrote:
> >
> > On Tue, 10 Sep 2019 21:44:11 -0500
> > Jassi Brar <jassisinghbrar@gmail.com> wrote:
> >
> > Hi,
> >
> > > On Mon, Sep 9, 2019 at 10:42 AM Andre Przywara
> <andre.przywara@arm.com> wrote:
> > > >
> > > > On Wed, 28 Aug 2019 03:02:58 +0000 Peng Fan <peng.fan@nxp.com>
> > > > wrote:
> > > >
> > [ ... ]
> > > >
> > > > > +
> > > > > +  arm,func-ids:
> > > > > +    description: |
> > > > > +      An array of 32-bit values specifying the function IDs used by
> each
> > > > > +      mailbox channel. Those function IDs follow the ARM SMC
> calling
> > > > > +      convention standard [1].
> > > > > +
> > > > > +      There is one identifier per channel and the number of
> supported
> > > > > +      channels is determined by the length of this array.
> > > >
> > > > I think this makes it obvious that arm,num-chans is not needed.
> > > >
> > > > Also this somewhat contradicts the driver implementation, which allows
> the array to be shorter, marking this as UINT_MAX and later on using the first
> data item as a function identifier. This is somewhat surprising and not
> documented (unless I missed something).
> > > >
> > > > So I would suggest:
> > > > - We drop the transports property, and always put the client provided
> data in the registers, according to the SMCCC. Document this here.
> > > >   A client not needing those could always puts zeros (or garbage) in
> there, the respective firmware would just ignore the registers.
> > > > - We drop "arm,num-chans", as this is just redundant with the length of
> the func-ids array.
> > > > - We don't impose an arbitrary limit on the number of channels. From
> the firmware point of view this is just different function IDs, from Linux' point
> of view just the size of the memory used. Both don't need to be limited
> artificially IMHO.
> > > >
> > > Sounds like we are in sync.
> > >
> > > > - We mark arm,func-ids as required, as this needs to be fixed, allocated
> number.
> > > >
> > > I still think func-id can be done without. A client can always pass
> > > the value as it knows what it expects.
> >
> > I don't think it's the right abstraction. The mailbox *controller* uses a
> specific func-id, this has to match the one the firmware expects. So this is a
> property of the mailbox transport channel (the SMC call), and the *client*
> should *not* care about it. It just sees the logical channel ID (if we have one),
> which the controller translates into the func-ID.
> >
> arg0 is special only to the client/protocol, otherwise it is simply the first
> argument for the arm_smccc_smc *instruction* controller.
> arg[1,7] are already provided by the client, so it is only neater if
> arg0 is also taken from the client.
> 
> But as I said, I am still ok if func-id is passed from dt and arg0 from client is
> ignored because we have one channel per controller design and we don't have
> to worry about number of channels there can be dedicated to specific
> functions.

Ok, so I'll make it an optional property.

> 
> > So it should really look like this (assuming only single channel controllers):
> > mailbox: smc-mailbox {
> >     #mbox-cells = <0>;
> >     compatible = "arm,smc-mbox";
> >     method = "smc";
> >
> Do we want to do away with 'method' property and use different 'compatible'
> properties instead?
>  compatible = "arm,smc-mbox";     or    compatible = "arm,hvc-mbox";

I am ok, just need add data in driver to differentiate smc/hvc.
Andre, are you ok?

Thanks,
Peng.

> 
> >     arm,func-id = <0x820000fe>;
> > };
> > scmi {
> >     compatible = "arm,scmi";
> >     mboxes = <&smc_mbox>;
> >     mbox-names = "tx"; /* rx is optional */
> >     shmem = <&cpu_scp_hpri>;
> > };
> >
> > If you allow the client to provide the function ID (and I am not saying this is
> a good idea): where would this func ID come from? It would need to be a
> property of the client DT node, then. So one way would be to use the func ID
> as the Linux mailbox channel ID:
> > mailbox: smc-mailbox {
> >     #mbox-cells = <1>;
> >     compatible = "arm,smc-mbox";
> >     method = "smc";
> > };
> > scmi {
> >     compatible = "arm,scmi";
> >     mboxes = <&smc_mbox 0x820000fe>;
> >     mbox-names = "tx"; /* rx is optional */
> >     shmem = <&cpu_scp_hpri>;
> > };
> >
> > But this doesn't look desirable.
> >
> > And as I mentioned this before: allowing some mailbox clients to provide
> the function IDs sound scary, as they could use anything they want, triggering
> random firmware actions (think PSCI_CPU_OFF).
> >
> That paranoia is unwarranted. We have to keep faith in kernel-space code
> doing the right thing.
> Either the illegitimate function request should be rejected by the firmware or
> client driver be called buggy.... just as we would call a block device driver
> buggy if it messed up the sector numbers in a write request.
> 
> thnx.
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH 1/2] ARM: dts: imx7d: Correct speed grading fuse settings
From: Anson Huang @ 2019-09-12  2:56 UTC (permalink / raw)
  To: robh+dt, mark.rutland, shawnguo, s.hauer, kernel, festevam,
	devicetree, linux-arm-kernel, linux-kernel
  Cc: Linux-imx

The 800MHz opp speed grading fuse mask should be 0xd instead
of 0xf according to fuse map definition:

SPEED_GRADING[1:0]	MHz
	00		800
	01		500
	10		1000
	11		1200

Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
 arch/arm/boot/dts/imx7d.dtsi | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi
index 9c8dd32..0083272 100644
--- a/arch/arm/boot/dts/imx7d.dtsi
+++ b/arch/arm/boot/dts/imx7d.dtsi
@@ -43,7 +43,7 @@
 			opp-hz = /bits/ 64 <792000000>;
 			opp-microvolt = <1000000>;
 			clock-latency-ns = <150000>;
-			opp-supported-hw = <0xf>, <0xf>;
+			opp-supported-hw = <0xd>, <0xf>;
 		};
 
 		opp-996000000 {
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH 2/2] ARM: dts: imx7d: Add opp-suspend property
From: Anson Huang @ 2019-09-12  2:56 UTC (permalink / raw)
  To: robh+dt, mark.rutland, shawnguo, s.hauer, kernel, festevam,
	devicetree, linux-arm-kernel, linux-kernel
  Cc: Linux-imx
In-Reply-To: <1568256992-31707-1-git-send-email-Anson.Huang@nxp.com>

Add "opp-suspend" property for i.MX7D to make sure system
suspend with max available opp.

Signed-off-by: Anson Huang <Anson.Huang@nxp.com>
---
 arch/arm/boot/dts/imx7d.dtsi | 3 +++
 1 file changed, 3 insertions(+)

diff --git a/arch/arm/boot/dts/imx7d.dtsi b/arch/arm/boot/dts/imx7d.dtsi
index 0083272..2792767 100644
--- a/arch/arm/boot/dts/imx7d.dtsi
+++ b/arch/arm/boot/dts/imx7d.dtsi
@@ -44,6 +44,7 @@
 			opp-microvolt = <1000000>;
 			clock-latency-ns = <150000>;
 			opp-supported-hw = <0xd>, <0xf>;
+			opp-suspend;
 		};
 
 		opp-996000000 {
@@ -51,6 +52,7 @@
 			opp-microvolt = <1100000>;
 			clock-latency-ns = <150000>;
 			opp-supported-hw = <0xc>, <0xf>;
+			opp-suspend;
 		};
 
 		opp-1200000000 {
@@ -58,6 +60,7 @@
 			opp-microvolt = <1225000>;
 			clock-latency-ns = <150000>;
 			opp-supported-hw = <0x8>, <0xf>;
+			opp-suspend;
 		};
 	};
 
-- 
2.7.4


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [PATCH] dts: arm64: imx8mq: Enable gpu passive throttling
From: Guido Günther @ 2019-09-12  2:42 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Lucas Stach, Abel Vesa, Anson Huang, Carlo Caione,
	Angus Ainslie (Purism), Andrey Smirnov, devicetree,
	linux-arm-kernel, linux-kernel
In-Reply-To: <cf1b114bcc6ef26e032c352b8c885aaf5f3594d0.1568254197.git.agx@sigxcpu.org>

Hi,
On Wed, Sep 11, 2019 at 07:14:25PM -0700, Guido Günther wrote:
> Temperature and hysteresis were picked after the CPU.

I pulled that one from the wrong branch so please disregard. I've
sent out a v2.
Cheers,
 -- Guido

> 
> Signed-off-by: Guido Günther <agx@sigxcpu.org>
> ---
>  arch/arm64/boot/dts/freescale/imx8mq.dtsi | 15 +++++++++++++++
>  1 file changed, 15 insertions(+)
> 
> diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
> index 564045927485..fda636085bb3 100644
> --- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
> +++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
> @@ -235,12 +235,26 @@
>  			thermal-sensors = <&tmu 1>;
>  
>  			trips {
> +				gpu-alert {
> +					temperature = <80000>;
> +					hysteresis = <2000>;
> +					type = "passive";
> +				};
> +
>  				gpu-crit {
>  					temperature = <90000>;
>  					hysteresis = <2000>;
>  					type = "critical";
>  				};
>  			};
> +
> +			cooling-maps {
> +				map0 {
> +					trip = <&gpu_alert>;
> +					cooling-device =
> +						<&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
> +				};
> +			};
>  		};
>  
>  		vpu-thermal {
> @@ -1006,6 +1020,7 @@
>  			         <&clk IMX8MQ_CLK_GPU_AXI>,
>  			         <&clk IMX8MQ_CLK_GPU_AHB>;
>  			clock-names = "core", "shader", "bus", "reg";
> +			#cooling-cells = <2>;
>  			assigned-clocks = <&clk IMX8MQ_CLK_GPU_CORE_SRC>,
>  			                  <&clk IMX8MQ_CLK_GPU_SHADER_SRC>,
>  			                  <&clk IMX8MQ_CLK_GPU_AXI>,
> -- 
> 2.23.0.rc1
> 
> 
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH v2 2/2] dt-bindings: etnaviv: Add #cooling-cells
From: Guido Günther @ 2019-09-12  2:40 UTC (permalink / raw)
  To: To : Lucas Stach, Russell King, Christian Gmeiner, David Airlie,
	Daniel Vetter, Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team, Abel Vesa,
	Anson Huang, Carlo Caione, Guido Günther, Andrey Smirnov,
	Angus Ainslie (Purism), etnaviv, dri-devel, devicetree,
	linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1568255903.git.agx@sigxcpu.org>

Add #cooling-cells for when the gpu acts as a cooling device.

Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
 .../devicetree/bindings/display/etnaviv/etnaviv-drm.txt          | 1 +
 1 file changed, 1 insertion(+)

diff --git a/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt b/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt
index 8def11b16a24..640592e8ab2e 100644
--- a/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt
+++ b/Documentation/devicetree/bindings/display/etnaviv/etnaviv-drm.txt
@@ -21,6 +21,7 @@ Required properties:
 Optional properties:
 - power-domains: a power domain consumer specifier according to
   Documentation/devicetree/bindings/power/power_domain.txt
+- #cooling-cells: : If used as a cooling device, must be <2>
 
 example:
 
-- 
2.23.0.rc1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v2 1/2] dts: arm64: imx8mq: Enable gpu passive throttling
From: Guido Günther @ 2019-09-12  2:40 UTC (permalink / raw)
  To: To : Lucas Stach, Russell King, Christian Gmeiner, David Airlie,
	Daniel Vetter, Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team, Abel Vesa,
	Anson Huang, Carlo Caione, Guido Günther, Andrey Smirnov,
	Angus Ainslie (Purism), etnaviv, dri-devel, devicetree,
	linux-kernel, linux-arm-kernel
In-Reply-To: <cover.1568255903.git.agx@sigxcpu.org>

Temperature and hysteresis were picked after the CPU.

Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
 arch/arm64/boot/dts/freescale/imx8mq.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
index 4fdd60f2c51e..5023a0e5068d 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
@@ -235,12 +235,26 @@
 			thermal-sensors = <&tmu 1>;
 
 			trips {
+				gpu_alert: gpu-alert {
+					temperature = <80000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
 				gpu-crit {
 					temperature = <90000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&gpu_alert>;
+					cooling-device =
+						<&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
 		};
 
 		vpu-thermal {
@@ -912,6 +926,7 @@
 			         <&clk IMX8MQ_CLK_GPU_AXI>,
 			         <&clk IMX8MQ_CLK_GPU_AHB>;
 			clock-names = "core", "shader", "bus", "reg";
+			#cooling-cells = <2>;
 			assigned-clocks = <&clk IMX8MQ_CLK_GPU_CORE_SRC>,
 			                  <&clk IMX8MQ_CLK_GPU_SHADER_SRC>,
 			                  <&clk IMX8MQ_CLK_GPU_AXI>,
-- 
2.23.0.rc1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* [PATCH v2 0/2] dts: arm64: imx8mq: Enable gpu passive throttling
From: Guido Günther @ 2019-09-12  2:40 UTC (permalink / raw)
  To: To : Lucas Stach, Russell King, Christian Gmeiner, David Airlie,
	Daniel Vetter, Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team, Abel Vesa,
	Anson Huang, Carlo Caione, Guido Günther, Andrey Smirnov,
	Angus Ainslie (Purism), etnaviv, dri-devel, devicetree,
	linux-kernel, linux-arm-kernel

Temperature and hysteresis were picked after the CPU.

Changes from v1:
 - Update dt bindings
 - Fix broken phandle

Guido Günther (2):
  dts: arm64: imx8mq: Enable gpu passive throttling
  dt-bindings: etnaviv: Add #cooling-cells

 .../bindings/display/etnaviv/etnaviv-drm.txt      |  1 +
 arch/arm64/boot/dts/freescale/imx8mq.dtsi         | 15 +++++++++++++++
 2 files changed, 16 insertions(+)

-- 
2.23.0.rc1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* CONFIG_SHUFFLE_PAGE_ALLOCATOR=y lockdep splat (WAS Re: page_alloc.shuffle=1 + CONFIG_PROVE_LOCKING=y = arm64 hang)
From: Qian Cai @ 2019-09-12  2:28 UTC (permalink / raw)
  To: Will Deacon, Theodore Ts'o, oleg, gkohli
  Cc: Peter Zijlstra, LKML, Linux Memory Management List, Waiman Long,
	Dan Williams, Thomas Gleixner, linux-arm-kernel
In-Reply-To: <1568144988.5576.132.camel@lca.pw>

Adjusted Cc a bit as this looks like more of the scheduler territory.

> On Sep 10, 2019, at 3:49 PM, Qian Cai <cai@lca.pw> wrote:
> 
> Hmm, it feels like that CONFIG_SHUFFLE_PAGE_ALLOCATOR=y introduces some unique
> locking patterns that the lockdep does not like via,
> 
> allocate_slab
>  shuffle_freelist
>    get_random_u32
> 
> Here is another splat with while compiling/installing a kernel,
> 
> [ 1254.443119][    C2] WARNING: possible circular locking dependency detected
> [ 1254.450038][    C2] 5.3.0-rc5-next-20190822 #1 Not tainted
> [ 1254.455559][    C2] ------------------------------------------------------
> [ 1254.462988][    C2] swapper/2/0 is trying to acquire lock:
> [ 1254.468509][    C2] ffffffffa2925218 (random_write_wait.lock){..-.}, at:
> __wake_up_common_lock+0xc6/0x150
> [ 1254.478154][    C2] 
> [ 1254.478154][    C2] but task is already holding lock:
> [ 1254.485896][    C2] ffff88845373fda0 (batched_entropy_u32.lock){-.-.}, at:
> get_random_u32+0x4c/0xe0
> [ 1254.495007][    C2] 
> [ 1254.495007][    C2] which lock already depends on the new lock.
> [ 1254.495007][    C2] 
> [ 1254.505331][    C2] 
> [ 1254.505331][    C2] the existing dependency chain (in reverse order) is:
> [ 1254.514755][    C2] 
> [ 1254.514755][    C2] -> #3 (batched_entropy_u32.lock){-.-.}:
> [ 1254.522553][    C2]        __lock_acquire+0x5b3/0xb40
> [ 1254.527638][    C2]        lock_acquire+0x126/0x280
> [ 1254.533016][    C2]        _raw_spin_lock_irqsave+0x3a/0x50
> [ 1254.538624][    C2]        get_random_u32+0x4c/0xe0
> [ 1254.543539][    C2]        allocate_slab+0x6d6/0x19c0
> [ 1254.548625][    C2]        new_slab+0x46/0x70
> [ 1254.553010][    C2]        ___slab_alloc+0x58b/0x960
> [ 1254.558533][    C2]        __slab_alloc+0x43/0x70
> [ 1254.563269][    C2]        kmem_cache_alloc+0x354/0x460
> [ 1254.568534][    C2]        fill_pool+0x272/0x4b0
> [ 1254.573182][    C2]        __debug_object_init+0x86/0x7a0
> [ 1254.578615][    C2]        debug_object_init+0x16/0x20
> [ 1254.584256][    C2]        hrtimer_init+0x27/0x1e0
> [ 1254.589079][    C2]        init_dl_task_timer+0x20/0x40
> [ 1254.594342][    C2]        __sched_fork+0x10b/0x1f0
> [ 1254.599253][    C2]        init_idle+0xac/0x520
> [ 1254.603816][    C2]        fork_idle+0x18c/0x230
> [ 1254.608933][    C2]        idle_threads_init+0xf0/0x187
> [ 1254.614193][    C2]        smp_init+0x1d/0x12d
> [ 1254.618671][    C2]        kernel_init_freeable+0x37e/0x76e
> [ 1254.624282][    C2]        kernel_init+0x11/0x12f
> [ 1254.629016][    C2]        ret_from_fork+0x27/0x50
> [ 1254.634344][    C2] 
> [ 1254.634344][    C2] -> #2 (&rq->lock){-.-.}:
> [ 1254.640831][    C2]        __lock_acquire+0x5b3/0xb40
> [ 1254.645917][    C2]        lock_acquire+0x126/0x280
> [ 1254.650827][    C2]        _raw_spin_lock+0x2f/0x40
> [ 1254.655741][    C2]        task_fork_fair+0x43/0x200
> [ 1254.661213][    C2]        sched_fork+0x29b/0x420
> [ 1254.665949][    C2]        copy_process+0xf12/0x3180
> [ 1254.670947][    C2]        _do_fork+0xef/0x950
> [ 1254.675422][    C2]        kernel_thread+0xa8/0xe0
> [ 1254.680244][    C2]        rest_init+0x28/0x311
> [ 1254.685298][    C2]        arch_call_rest_init+0xe/0x1b
> [ 1254.690558][    C2]        start_kernel+0x6eb/0x724
> [ 1254.695469][    C2]        x86_64_start_reservations+0x24/0x26
> [ 1254.701339][    C2]        x86_64_start_kernel+0xf4/0xfb
> [ 1254.706689][    C2]        secondary_startup_64+0xb6/0xc0
> [ 1254.712601][    C2] 
> [ 1254.712601][    C2] -> #1 (&p->pi_lock){-.-.}:
> [ 1254.719263][    C2]        __lock_acquire+0x5b3/0xb40
> [ 1254.724349][    C2]        lock_acquire+0x126/0x280
> [ 1254.729260][    C2]        _raw_spin_lock_irqsave+0x3a/0x50
> [ 1254.735317][    C2]        try_to_wake_up+0xad/0x1050
> [ 1254.740403][    C2]        default_wake_function+0x2f/0x40
> [ 1254.745929][    C2]        pollwake+0x10d/0x160
> [ 1254.750491][    C2]        __wake_up_common+0xc4/0x2a0
> [ 1254.755663][    C2]        __wake_up_common_lock+0xea/0x150
> [ 1254.761756][    C2]        __wake_up+0x13/0x20
> [ 1254.766230][    C2]        account.constprop.9+0x217/0x340
> [ 1254.771754][    C2]        extract_entropy.constprop.7+0xcf/0x220
> [ 1254.777886][    C2]        _xfer_secondary_pool+0x19a/0x3d0
> [ 1254.783981][    C2]        push_to_pool+0x3e/0x230
> [ 1254.788805][    C2]        process_one_work+0x52a/0xb40
> [ 1254.794064][    C2]        worker_thread+0x63/0x5b0
> [ 1254.798977][    C2]        kthread+0x1df/0x200
> [ 1254.803451][    C2]        ret_from_fork+0x27/0x50
> [ 1254.808787][    C2] 
> [ 1254.808787][    C2] -> #0 (random_write_wait.lock){..-.}:
> [ 1254.816409][    C2]        check_prev_add+0x107/0xea0
> [ 1254.821494][    C2]        validate_chain+0x8fc/0x1200
> [ 1254.826667][    C2]        __lock_acquire+0x5b3/0xb40
> [ 1254.831751][    C2]        lock_acquire+0x126/0x280
> [ 1254.837189][    C2]        _raw_spin_lock_irqsave+0x3a/0x50
> [ 1254.842797][    C2]        __wake_up_common_lock+0xc6/0x150
> [ 1254.848408][    C2]        __wake_up+0x13/0x20
> [ 1254.852882][    C2]        account.constprop.9+0x217/0x340
> [ 1254.858988][    C2]        extract_entropy.constprop.7+0xcf/0x220
> [ 1254.865122][    C2]        crng_reseed+0xa1/0x3f0
> [ 1254.869859][    C2]        _extract_crng+0xc3/0xd0
> [ 1254.874682][    C2]        crng_reseed+0x21b/0x3f0
> [ 1254.879505][    C2]        _extract_crng+0xc3/0xd0
> [ 1254.884772][    C2]        extract_crng+0x40/0x60
> [ 1254.889507][    C2]        get_random_u32+0xb4/0xe0
> [ 1254.894417][    C2]        allocate_slab+0x6d6/0x19c0
> [ 1254.899501][    C2]        new_slab+0x46/0x70
> [ 1254.903886][    C2]        ___slab_alloc+0x58b/0x960
> [ 1254.909377][    C2]        __slab_alloc+0x43/0x70
> [ 1254.914112][    C2]        kmem_cache_alloc+0x354/0x460
> [ 1254.919375][    C2]        __build_skb+0x23/0x60
> [ 1254.924024][    C2]        __netdev_alloc_skb+0x127/0x1e0
> [ 1254.929470][    C2]        tg3_poll_work+0x11b2/0x1f70 [tg3]
> [ 1254.935654][    C2]        tg3_poll_msix+0x67/0x330 [tg3]
> [ 1254.941092][    C2]        net_rx_action+0x24e/0x7e0
> [ 1254.946089][    C2]        __do_softirq+0x123/0x767
> [ 1254.951000][    C2]        irq_exit+0xd6/0xf0
> [ 1254.955385][    C2]        do_IRQ+0xe2/0x1a0
> [ 1254.960155][    C2]        ret_from_intr+0x0/0x2a
> [ 1254.964896][    C2]        cpuidle_enter_state+0x156/0x8e0
> [ 1254.970418][    C2]        cpuidle_enter+0x41/0x70
> [ 1254.975242][    C2]        call_cpuidle+0x5e/0x90
> [ 1254.979975][    C2]        do_idle+0x333/0x370
> [ 1254.984972][    C2]        cpu_startup_entry+0x1d/0x1f
> [ 1254.990148][    C2]        start_secondary+0x290/0x330
> [ 1254.995319][    C2]        secondary_startup_64+0xb6/0xc0
> [ 1255.000750][    C2] 
> [ 1255.000750][    C2] other info that might help us debug this:
> [ 1255.000750][    C2] 
> [ 1255.011424][    C2] Chain exists of:
> [ 1255.011424][    C2]   random_write_wait.lock --> &rq->lock -->
> batched_entropy_u32.lock
> [ 1255.011424][    C2] 
> [ 1255.025245][    C2]  Possible unsafe locking scenario:
> [ 1255.025245][    C2] 
> [ 1255.033012][    C2]        CPU0                    CPU1
> [ 1255.038270][    C2]        ----                    ----
> [ 1255.043526][    C2]   lock(batched_entropy_u32.lock);
> [ 1255.048610][    C2]                                lock(&rq->lock);
> [
> 1255.054918][    C2]                                lock(batched_entropy_u32.loc
> k);
> [ 1255.063035][    C2]   lock(random_write_wait.lock);
> [ 1255.067945][    C2] 
> [ 1255.067945][    C2]  *** DEADLOCK ***
> [ 1255.067945][    C2] 
> [ 1255.076000][    C2] 1 lock held by swapper/2/0:
> [ 1255.080558][    C2]  #0: ffff88845373fda0 (batched_entropy_u32.lock){-.-.},
> at: get_random_u32+0x4c/0xe0
> [ 1255.090547][    C2] 
> [ 1255.090547][    C2] stack backtrace:
> [ 1255.096333][    C2] CPU: 2 PID: 0 Comm: swapper/2 Not tainted 5.3.0-rc5-next-
> 20190822 #1
> [ 1255.104473][    C2] Hardware name: HPE ProLiant DL385 Gen10/ProLiant DL385
> Gen10, BIOS A40 03/09/2018
> [ 1255.114276][    C2] Call Trace:
> [ 1255.117439][    C2]  <IRQ>
> [ 1255.120169][    C2]  dump_stack+0x86/0xca
> [ 1255.124205][    C2]  print_circular_bug.cold.32+0x243/0x26e
> [ 1255.129816][    C2]  check_noncircular+0x29e/0x2e0
> [ 1255.135221][    C2]  ? __bfs+0x238/0x380
> [ 1255.139172][    C2]  ? print_circular_bug+0x120/0x120
> [ 1255.144259][    C2]  ? find_usage_forwards+0x7d/0xb0
> [ 1255.149260][    C2]  check_prev_add+0x107/0xea0
> [ 1255.153823][    C2]  validate_chain+0x8fc/0x1200
> [ 1255.159007][    C2]  ? check_prev_add+0xea0/0xea0
> [ 1255.163743][    C2]  ? check_usage_backwards+0x210/0x210
> [ 1255.169091][    C2]  __lock_acquire+0x5b3/0xb40
> [ 1255.173655][    C2]  lock_acquire+0x126/0x280
> [ 1255.178041][    C2]  ? __wake_up_common_lock+0xc6/0x150
> [ 1255.183732][    C2]  _raw_spin_lock_irqsave+0x3a/0x50
> [ 1255.188817][    C2]  ? __wake_up_common_lock+0xc6/0x150
> [ 1255.194076][    C2]  __wake_up_common_lock+0xc6/0x150
> [ 1255.199163][    C2]  ? __wake_up_common+0x2a0/0x2a0
> [ 1255.204078][    C2]  ? rcu_read_lock_any_held.part.5+0x20/0x20
> [ 1255.210428][    C2]  __wake_up+0x13/0x20
> [ 1255.214379][    C2]  account.constprop.9+0x217/0x340
> [ 1255.219377][    C2]  extract_entropy.constprop.7+0xcf/0x220
> [ 1255.224987][    C2]  ? crng_reseed+0xa1/0x3f0
> [ 1255.229375][    C2]  crng_reseed+0xa1/0x3f0
> [ 1255.234122][    C2]  ? rcu_read_lock_sched_held+0xac/0xe0
> [ 1255.239556][    C2]  ? check_flags.part.16+0x86/0x220
> [ 1255.244641][    C2]  ? extract_entropy.constprop.7+0x220/0x220
> [ 1255.250511][    C2]  ? __kasan_check_read+0x11/0x20
> [ 1255.255422][    C2]  ? validate_chain+0xab/0x1200
> [ 1255.260742][    C2]  ? rcu_read_lock_any_held.part.5+0x20/0x20
> [ 1255.266616][    C2]  _extract_crng+0xc3/0xd0
> [ 1255.270915][    C2]  crng_reseed+0x21b/0x3f0
> [ 1255.275215][    C2]  ? extract_entropy.constprop.7+0x220/0x220
> [ 1255.281085][    C2]  ? __kasan_check_write+0x14/0x20
> [ 1255.286517][    C2]  ? do_raw_spin_lock+0x118/0x1d0
> [ 1255.291428][    C2]  ? rwlock_bug.part.0+0x60/0x60
> [ 1255.296251][    C2]  _extract_crng+0xc3/0xd0
> [ 1255.300550][    C2]  extract_crng+0x40/0x60
> [ 1255.304763][    C2]  get_random_u32+0xb4/0xe0
> [ 1255.309640][    C2]  allocate_slab+0x6d6/0x19c0
> [ 1255.314203][    C2]  new_slab+0x46/0x70
> [ 1255.318066][    C2]  ___slab_alloc+0x58b/0x960
> [ 1255.322539][    C2]  ? __build_skb+0x23/0x60
> [ 1255.326841][    C2]  ? fault_create_debugfs_attr+0x140/0x140
> [ 1255.333048][    C2]  ? __build_skb+0x23/0x60
> [ 1255.337348][    C2]  __slab_alloc+0x43/0x70
> [ 1255.341559][    C2]  ? __slab_alloc+0x43/0x70
> [ 1255.345944][    C2]  ? __build_skb+0x23/0x60
> [ 1255.350242][    C2]  kmem_cache_alloc+0x354/0x460
> [ 1255.354978][    C2]  ? __netdev_alloc_skb+0x1c6/0x1e0
> [ 1255.360626][    C2]  ? trace_hardirqs_on+0x3a/0x160
> [ 1255.365535][    C2]  __build_skb+0x23/0x60
> [ 1255.369660][    C2]  __netdev_alloc_skb+0x127/0x1e0
> [ 1255.374576][    C2]  tg3_poll_work+0x11b2/0x1f70 [tg3]
> [ 1255.379750][    C2]  ? find_held_lock+0x11b/0x150
> [ 1255.385027][    C2]  ? tg3_tx_recover+0xa0/0xa0 [tg3]
> [ 1255.390114][    C2]  ? _raw_spin_unlock_irqrestore+0x38/0x50
> [ 1255.395809][    C2]  ? __kasan_check_read+0x11/0x20
> [ 1255.400718][    C2]  ? validate_chain+0xab/0x1200
> [ 1255.405455][    C2]  ? __wake_up_common+0x2a0/0x2a0
> [ 1255.410761][    C2]  ? mark_held_locks+0x34/0xb0
> [ 1255.415415][    C2]  tg3_poll_msix+0x67/0x330 [tg3]
> [ 1255.420327][    C2]  net_rx_action+0x24e/0x7e0
> [ 1255.424800][    C2]  ? find_held_lock+0x11b/0x150
> [ 1255.429536][    C2]  ? napi_busy_loop+0x600/0x600
> [ 1255.434733][    C2]  ? rcu_read_lock_sched_held+0xac/0xe0
> [ 1255.440169][    C2]  ? __do_softirq+0xed/0x767
> [ 1255.444642][    C2]  ? rcu_read_lock_any_held.part.5+0x20/0x20
> [ 1255.450518][    C2]  ? lockdep_hardirqs_on+0x1b0/0x2a0
> [ 1255.455693][    C2]  ? irq_exit+0xd6/0xf0
> [ 1255.460280][    C2]  __do_softirq+0x123/0x767
> [ 1255.464668][    C2]  irq_exit+0xd6/0xf0
> [ 1255.468532][    C2]  do_IRQ+0xe2/0x1a0
> [ 1255.472308][    C2]  common_interrupt+0xf/0xf
> [ 1255.476694][    C2]  </IRQ>
> [ 1255.479509][    C2] RIP: 0010:cpuidle_enter_state+0x156/0x8e0
> [ 1255.485750][    C2] Code: bf ff 8b 05 a4 27 2d 01 85 c0 0f 8f 1d 04 00 00 31
> ff e8 4d ba 92 ff 80 7d d0 00 0f 85 0b 02 00 00 e8 ae c0 a7 ff fb 45 85 ed <0f>
> 88 2d 02 00 00 4d 63 fd 49 83 ff 09 0f 87 91 06 00 00 4b 8d 04
> [ 1255.505335][    C2] RSP: 0018:ffff888206637cf8 EFLAGS: 00000202 ORIG_RAX:
> ffffffffffffffc8
> [ 1255.514154][    C2] RAX: 0000000000000000 RBX: ffff889f98b44008 RCX:
> ffffffffa116e980
> [ 1255.522033][    C2] RDX: 0000000000000007 RSI: dffffc0000000000 RDI:
> ffff8882066287ec
> [ 1255.529913][    C2] RBP: ffff888206637d48 R08: fffffbfff4557aee R09:
> 0000000000000000
> [ 1255.538278][    C2] R10: 0000000000000000 R11: 0000000000000000 R12:
> ffffffffa28e8ac0
> [ 1255.546158][    C2] R13: 0000000000000002 R14: 0000012412160253 R15:
> ffff889f98b4400c
> [ 1255.554040][    C2]  ? lockdep_hardirqs_on+0x1b0/0x2a0
> [ 1255.559725][    C2]  ? cpuidle_enter_state+0x152/0x8e0
> [ 1255.564898][    C2]  cpuidle_enter+0x41/0x70
> [ 1255.569196][    C2]  call_cpuidle+0x5e/0x90
> [ 1255.573408][    C2]  do_idle+0x333/0x370
> [ 1255.577358][    C2]  ? complete+0x51/0x60
> [ 1255.581394][    C2]  ? arch_cpu_idle_exit+0x40/0x40
> [ 1255.586777][    C2]  ? complete+0x51/0x60
> [ 1255.590814][    C2]  cpu_startup_entry+0x1d/0x1f
> [ 1255.595461][    C2]  start_secondary+0x290/0x330
> [ 1255.600111][    C2]  ? set_cpu_sibling_map+0x18f0/0x18f0
> [ 1255.605460][    C2]  secondary_startup_64+0xb6/0xc0

This looks like a false positive. shuffle_freelist() introduced the chain,

batched_entropy_u32.lock -> random_write_wait.lock

but I can’t see how it is possible to get the reversed chain. Imaging something like this,

 __wake_up_common_lock  <— acquired random_write_wait.lock
      __sched_fork <— is that even possible?
           init_dl_task_timer
              debug_object_init
                   allocate_slab
                      shuffle_freelist
                          get_random_u32 <— acquired batched_entropy_u32.lock
_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* RE: [PATCH v1 1/3] scsi: core: allow auto suspend override by low-level driver
From: Stanley Chu @ 2019-09-12  2:24 UTC (permalink / raw)
  To: Avri Altman
  Cc: sthumma@codeaurora.org, linux-scsi@vger.kernel.org,
	martin.petersen@oracle.com, marc.w.gonzalez@free.fr,
	vivek.gautam@codeaurora.org, Andy Teng (^[$B{}G!9(^[(B),
	jejb@linux.ibm.com, Chun-Hung Wu (巫駿宏),
	Kuohong Wang (王國鴻), evgreen@chromium.org,
	subhashj@codeaurora.org, linux-mediatek@lists.infradead.org,
	Peter Wang (王信友), alim.akhtar@samsung.com,
	matthias.bgg@gmail.com, beanhuo@micron.com,
	pedrom.sousa@synopsys.com, linux-arm-kernel@lists.infradead.org,
	bvanassche@acm.org
In-Reply-To: <MN2PR04MB6991142450EEF05E2AF2D8DFFCB10@MN2PR04MB6991.namprd04.prod.outlook.com>

Hi Avri,

> > diff --git a/drivers/scsi/sd.c b/drivers/scsi/sd.c index
> > 149d406aacc9..2218d57c4c0c 100644
> > --- a/drivers/scsi/sd.c
> > +++ b/drivers/scsi/sd.c
> > @@ -3371,6 +3371,9 @@ static int sd_probe(struct device *dev)
> >         }
> > 
> >         blk_pm_runtime_init(sdp->request_queue, dev);
> > +       if (sdp->rpm_autosuspend_delay > 0)
> > +               pm_runtime_set_autosuspend_delay(dev, 
> > +
> Redundant line ?

checkpatch reported "WARNING:LONG_LINE:line over 80 characters" when I
made this as oneline : (

> > + sdp->rpm_autosuspend_delay);
> Don't you need to call now pm_runtime_use_autosuspend() ?

dev->power.user_autosuspend was set by blk_pm_runtime_init() above, thus
pm_runtime_use_autosuspend() is not necessary here.

> 
> >         device_add_disk(dev, gd, NULL);
> >         if (sdkp->capacity)
> >                 sd_dif_config_host(sdkp); diff --git a/include/scsi/scsi_device.h
> > b/include/scsi/scsi_device.h index 202f4d6a4342..133b282fae5a 100644
> > --- a/include/scsi/scsi_device.h
> > +++ b/include/scsi/scsi_device.h
> > @@ -199,7 +199,7 @@ struct scsi_device {
> >         unsigned broken_fua:1;          /* Don't set FUA bit */
> >         unsigned lun_in_cdb:1;          /* Store LUN bits in CDB[1] */
> >         unsigned unmap_limit_for_ws:1;  /* Use the UNMAP limit for WRITE
> > SAME */
> > -
> > +       int rpm_autosuspend_delay;
> Can suspend be negative?

Yes, however negative delay value will block rpm.

Here we just use the same type as parameter "delay" of
pm_runtime_set_autosuspend() even though we do not set it as negative
value in this version.

But thank you so much to remind me that
pm_runtime_set_autosuspend_delay() can accept "zero" delay so we shall
allow "zero" sdev->rpm_autosuspend_delay as well.

I will fix it in v2.

> 
> >         atomic_t disk_events_disable_depth; /* disable depth for disk events */
> > 
> >         DECLARE_BITMAP(supported_events, SDEV_EVT_MAXBITS); /*
> > supported events */
> > --
> > 2.18.0
> 

Thanks,
Stanley



_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* [PATCH] dts: arm64: imx8mq: Enable gpu passive throttling
From: Guido Günther @ 2019-09-12  2:14 UTC (permalink / raw)
  To: Rob Herring, Mark Rutland, Shawn Guo, Sascha Hauer,
	Pengutronix Kernel Team, Fabio Estevam, NXP Linux Team,
	Lucas Stach, Abel Vesa, Guido Günther, Anson Huang,
	Carlo Caione, Angus Ainslie (Purism), Andrey Smirnov, devicetree,
	linux-arm-kernel, linux-kernel

Temperature and hysteresis were picked after the CPU.

Signed-off-by: Guido Günther <agx@sigxcpu.org>
---
 arch/arm64/boot/dts/freescale/imx8mq.dtsi | 15 +++++++++++++++
 1 file changed, 15 insertions(+)

diff --git a/arch/arm64/boot/dts/freescale/imx8mq.dtsi b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
index 564045927485..fda636085bb3 100644
--- a/arch/arm64/boot/dts/freescale/imx8mq.dtsi
+++ b/arch/arm64/boot/dts/freescale/imx8mq.dtsi
@@ -235,12 +235,26 @@
 			thermal-sensors = <&tmu 1>;
 
 			trips {
+				gpu-alert {
+					temperature = <80000>;
+					hysteresis = <2000>;
+					type = "passive";
+				};
+
 				gpu-crit {
 					temperature = <90000>;
 					hysteresis = <2000>;
 					type = "critical";
 				};
 			};
+
+			cooling-maps {
+				map0 {
+					trip = <&gpu_alert>;
+					cooling-device =
+						<&gpu THERMAL_NO_LIMIT THERMAL_NO_LIMIT>;
+				};
+			};
 		};
 
 		vpu-thermal {
@@ -1006,6 +1020,7 @@
 			         <&clk IMX8MQ_CLK_GPU_AXI>,
 			         <&clk IMX8MQ_CLK_GPU_AHB>;
 			clock-names = "core", "shader", "bus", "reg";
+			#cooling-cells = <2>;
 			assigned-clocks = <&clk IMX8MQ_CLK_GPU_CORE_SRC>,
 			                  <&clk IMX8MQ_CLK_GPU_SHADER_SRC>,
 			                  <&clk IMX8MQ_CLK_GPU_AXI>,
-- 
2.23.0.rc1


_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* RE: FYI: imx-sdma firmware is not compatible with SLUB slab allocator
From: Robin Gong @ 2019-09-12  2:06 UTC (permalink / raw)
  To: Jurgen Lambrecht, Leonard Crestez, Fabio Estevam
  Cc: Aisheng Dong, dl-linux-imx, linux-arm-kernel@lists.infradead.org
In-Reply-To: <dc06392b-8242-7d09-e0fe-49fb04849ebb@televic.com>

On 2019-9-3 22:32 Jurgen Lambrecht <J.Lambrecht@TELEVIC.com> wrote
> On 9/3/19 7:57 AM, Robin Gong wrote:
> > CAUTION: This Email originated from outside Televic. Do not click links or
> open attachments unless you recognize the sender and know the content is
> safe.
> >
> >
> > On 2019-8-29 14:24, Jurgen Lambrecht wrote:
> >> On 8/28/19 4:05 PM, Robin Gong wrote:
> >>> Could you help check if below commit in your side?
> >>> commit ebb853b1bd5f659b92c71dc6a9de44cfc37c78c0
> >>> Author: Lucas Stach<l.stach@pengutronix.de>
> >>> Date:   Tue Nov 6 03:40:28 2018 +0000
> >> yes, it's in.
> >>
> >> Also the 2 follow-up commits of Lucas Stach:
> >> 9063f5a99ea76f85935e3e453422d15e7be89b9e and
> >> 374f384bc66f7a928f11eb20c0518f0f3fc1ffd6.
> I had also already cherry picked your commit
> 3f5de4c7e16164a344a905649f08e8a90a68ff9f "dmaengine: imx-sdma:
> remove BD_INTR for channel0".
> 
> But also then kernel hangs at loading sdma FW.
> 
> (this looked the most interesting commit)
I identified this issue which caused by SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3
(41)exceed the structure sdma_script_start_addrs(40) so that illegal memory
touch, such as slob block header, thus kernel trap into while() loop forever
in slob_free(). Please see the below code piece in sdma_add_scripts().
        for (i = 0; i < sdma->script_number; i++)
                if (addr_arr[i] > 0)
                        saddr_arr[i] = addr_arr[i];
That issue was brought by commit a572460be9cf (dmaengine: imx-sdma:
Add support for version 3 firmware) because the SDMA_SCRIPT_ADDRS_ARRAY_SIZE_V3
(38->41 3 scripts added) not align with script number added in
sdma_script_start_addrs(2 scripts). Please have a try with
the below patch:
diff --git a/include/linux/platform_data/dma-imx-sdma.h b/include/linux/platform_data/dma-imx-sdma.h
index 6eaa53c..30e676b 100644
--- a/include/linux/platform_data/dma-imx-sdma.h
+++ b/include/linux/platform_data/dma-imx-sdma.h
@@ -51,7 +51,10 @@ struct sdma_script_start_addrs {
        /* End of v2 array */
        s32 zcanfd_2_mcu_addr;
        s32 zqspi_2_mcu_addr;
+       s32 mcu_2_ecspi_addr;
        /* End of v3 array */
+       s32 mcu_2_zqspi_addr;
+       /* End of v4 array */
 };

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply related

* Re: [RFC, v3, 1/4] dt-binding: mt8183: Add Mediatek MDP3 dt-bindings
From: CK Hu @ 2019-09-12  1:29 UTC (permalink / raw)
  To: Bibby Hsieh
  Cc: laurent.pinchart+renesas, Rynn.Wu, Jerry-ch.Chen, jungo.lin,
	hans.verkuil, Ping-Hsun Wu, frederic.chen, linux-media,
	devicetree, daoyuan huang, holmes.chiou, sj.huang, yuzhao,
	linux-mediatek, matthias.bgg, mchehab, linux-arm-kernel,
	Sean.Cheng, srv_heupstream, tfiga, christie.yu, zwisler
In-Reply-To: <20190911093406.5688-2-bibby.hsieh@mediatek.com>


Hi, Bibby:

On Wed, 2019-09-11 at 17:34 +0800, Bibby Hsieh wrote:
> From: daoyuan huang <daoyuan.huang@mediatek.com>
> 
> This patch adds DT binding document for Media Data Path 3 (MDP3)
> a unit in multimedia system used for scaling and color format convert.
> 
> Signed-off-by: Ping-Hsun Wu <ping-hsun.wu@mediatek.com>
> Signed-off-by: daoyuan huang <daoyuan.huang@mediatek.com>
> ---
>  .../bindings/media/mediatek,mt8183-mdp3.txt   | 201 ++++++++++++++++++
>  1 file changed, 201 insertions(+)
>  create mode 100644 Documentation/devicetree/bindings/media/mediatek,mt8183-mdp3.txt
> 
> diff --git a/Documentation/devicetree/bindings/media/mediatek,mt8183-mdp3.txt b/Documentation/devicetree/bindings/media/mediatek,mt8183-mdp3.txt
> new file mode 100644
> index 000000000000..0d15326d12c1
> --- /dev/null
> +++ b/Documentation/devicetree/bindings/media/mediatek,mt8183-mdp3.txt
> @@ -0,0 +1,201 @@
> +* Mediatek Media Data Path 3
> +
> +Media Data Path 3 (MDP3) is used for scaling and color space conversion.
> +
> +Required properties (controller node):
> +- compatible: "mediatek,mt8183-mdp"
> +- mediatek,scp: the node of system control processor (SCP), using the
> +  remoteproc & rpmsg framework, see
> +  Documentation/devicetree/bindings/remoteproc/mtk,scp.txt for details.
> +- mediatek,mmsys: the node of mux(multiplexer) controller for HW connections.
> +- mediatek,mm-mutex: the node of sof(start of frame) signal controller.
> +- mediatek,mailbox-gce: the node of global command engine (GCE), used to
> +  read/write registers with critical time limitation, see
> +  Documentation/devicetree/bindings/mailbox/mtk-gce.txt for details.
> +- mboxes: mailbox number used to communicate with GCE.
> +- gce-subsys: sub-system id corresponding to the register address.
> +- gce-event-names: in use event name list, used to correspond to event IDs.
> +- gce-events: in use event IDs list, all IDs are defined in
> +  'dt-bindings/gce/mt8183-gce.h'.
> +
> +Required properties (all function blocks, child node):
> +- compatible: Should be one of
> +        "mediatek,mt8183-mdp-rdma"  - read DMA
> +        "mediatek,mt8183-mdp-rsz"   - resizer
> +        "mediatek,mt8183-mdp-wdma"  - write DMA
> +        "mediatek,mt8183-mdp-wrot"  - write DMA with rotation
> +        "mediatek,mt8183-mdp-ccorr" - color correction with 3X3 matrix
> +- reg: Physical base address and length of the function block register space
> +- clocks: device clocks, see
> +  Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
> +- power-domains: a phandle to the power domain, see
> +  Documentation/devicetree/bindings/power/power_domain.txt for details.
> +- mediatek,mdp-id: HW index to distinguish same functionality modules.
> +
> +Required properties (DMA function blocks, child node):
> +- compatible: Should be one of
> +        "mediatek,mt8183-mdp-rdma"
> +        "mediatek,mt8183-mdp-wdma"
> +        "mediatek,mt8183-mdp-wrot"
> +- iommus: should point to the respective IOMMU block with master port as
> +  argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
> +  for details.
> +- mediatek,larb: must contain the local arbiters in the current Socs, see
> +  Documentation/devicetree/bindings/memory-controllers/mediatek,smi-larb.txt
> +  for details.
> +
> +Required properties (input path selection node):
> +- compatible:
> +        "mediatek,mt8183-mdp-dl"    - MDP direct link input source selection
> +- reg: Physical base address and length of the function block register space
> +- clocks: device clocks, see
> +  Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
> +- mediatek,mdp-id: HW index to distinguish same functionality modules.
> +
> +Required properties (ISP PASS2 (DIP) module path selection node):
> +- compatible:
> +        "mediatek,mt8183-mdp-imgi"  - input DMA of ISP PASS2 (DIP) module for raw image input
> +- reg: Physical base address and length of the function block register space
> +- mediatek,mdp-id: HW index to distinguish same functionality modules.
> +
> +Required properties (SW node):
> +- compatible: Should be one of
> +        "mediatek,mt8183-mdp-exto"  - output DMA of ISP PASS2 (DIP) module for yuv image output
> +        "mediatek,mt8183-mdp-path"  - MDP output path selection
> +- mediatek,mdp-id: HW index to distinguish same functionality modules.
> +
> +Example:
> +		mdp_camin@14000000 {
> +			compatible = "mediatek,mt8183-mdp-dl";
> +			mediatek,mdp-id = <0>;
> +			reg = <0 0x14000000 0 0x1000>;
> +			mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0 0x1000>;
> +			clocks = <&mmsys CLK_MM_MDP_DL_TXCK>,
> +				<&mmsys CLK_MM_MDP_DL_RX>;
> +		};
> +
> +		mdp_camin2@14000000 {
> +			compatible = "mediatek,mt8183-mdp-dl";
> +			mediatek,mdp-id = <1>;
> +			reg = <0 0x14000000 0 0x1000>;
> +			mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0 0x1000>;
> +			clocks = <&mmsys CLK_MM_IPU_DL_TXCK>,
> +				<&mmsys CLK_MM_IPU_DL_RX>;
> +		};

In [1], mmsys, mdp_camin, mdp_camin2 are at the same address
(0x14000000), so these three should be only one device (mmsys device
[2]). As I know, mmsys provide display clock control, display routing,
mdp clock control and mdp routing, but the binding just show the clock
part. I guess mdp_camin and mdp_camin2 here are the mdp routing part of
mmsys, so this should be moved to mmsys binding.


[1] https://patchwork.kernel.org/patch/11140747/
[2]
https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/Documentation/devicetree/bindings/arm/mediatek/mediatek,mmsys.txt?h=v5.3-rc8

Regards,
CK
> +
> +		mdp_rdma0: mdp_rdma0@14001000 {
> +			compatible = "mediatek,mt8183-mdp-rdma",
> +				     "mediatek,mt8183-mdp3";
> +			mediatek,scp = <&scp>;
> +			mediatek,mdp-id = <0>;
> +			reg = <0 0x14001000 0 0x1000>;
> +			mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x1000 0x1000>;
> +			power-domains = <&scpsys MT8183_POWER_DOMAIN_DISP>;
> +			clocks = <&mmsys CLK_MM_MDP_RDMA0>,
> +				<&mmsys CLK_MM_MDP_RSZ1>;
> +			iommus = <&iommu M4U_PORT_MDP_RDMA0>;
> +			mediatek,larb = <&larb0>;
> +			mediatek,mmsys = <&mmsys>;
> +			mediatek,mm-mutex = <&mutex>;
> +			mediatek,mailbox-gce = <&gce>;
> +			mboxes = <&gce 20 CMDQ_THR_PRIO_LOWEST 0>,
> +				<&gce 21 CMDQ_THR_PRIO_LOWEST 0>,
> +				<&gce 22 CMDQ_THR_PRIO_LOWEST 0>,
> +				<&gce 23 CMDQ_THR_PRIO_LOWEST 0>;
> +			gce-subsys = <&gce 0x14000000 SUBSYS_1400XXXX>,
> +				<&gce 0x14010000 SUBSYS_1401XXXX>,
> +				<&gce 0x14020000 SUBSYS_1402XXXX>,
> +				<&gce 0x15020000 SUBSYS_1502XXXX>;
> +			mediatek,gce-events = <CMDQ_EVENT_MDP_RDMA0_SOF>,
> +				<CMDQ_EVENT_MDP_RDMA0_EOF>,
> +				<CMDQ_EVENT_MDP_RSZ0_SOF>,
> +				<CMDQ_EVENT_MDP_RSZ1_SOF>,
> +				<CMDQ_EVENT_MDP_TDSHP_SOF>,
> +				<CMDQ_EVENT_MDP_WROT0_SOF>,
> +				<CMDQ_EVENT_MDP_WROT0_EOF>,
> +				<CMDQ_EVENT_MDP_WDMA0_SOF>,
> +				<CMDQ_EVENT_MDP_WDMA0_EOF>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_0>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_1>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_2>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_3>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_4>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_5>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_6>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_7>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_8>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_9>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_10>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_11>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_12>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_13>,
> +				<CMDQ_EVENT_ISP_FRAME_DONE_P2_14>,
> +				<CMDQ_EVENT_WPE_A_DONE>,
> +				<CMDQ_EVENT_SPE_B_DONE>;
> +		};
> +
> +		mdp_imgi@15020000 {
> +			compatible = "mediatek,mt8183-mdp-imgi";
> +			mediatek,mdp-id = <0>;
> +			reg = <0 0x15020000 0 0x1000>;
> +			mediatek,gce-client-reg = <&gce SUBSYS_1502XXXX 0 0x1000>;
> +		};
> +
> +		mdp_img2o@15020000 {
> +			compatible = "mediatek,mt8183-mdp-exto";
> +			mediatek,mdp-id = <1>;
> +		};
> +
> +		mdp_rsz0: mdp_rsz0@14003000 {
> +			compatible = "mediatek,mt8183-mdp-rsz";
> +			mediatek,mdp-id = <0>;
> +			reg = <0 0x14003000 0 0x1000>;
> +			mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x3000 0x1000>;
> +			clocks = <&mmsys CLK_MM_MDP_RSZ0>;
> +		};
> +
> +		mdp_rsz1: mdp_rsz1@14004000 {
> +			compatible = "mediatek,mt8183-mdp-rsz";
> +			mediatek,mdp-id = <1>;
> +			reg = <0 0x14004000 0 0x1000>;
> +			mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x4000 0x1000>;
> +			clocks = <&mmsys CLK_MM_MDP_RSZ1>;
> +		};
> +
> +		mdp_wrot0: mdp_wrot0@14005000 {
> +			compatible = "mediatek,mt8183-mdp-wrot";
> +			mediatek,mdp-id = <0>;
> +			reg = <0 0x14005000 0 0x1000>;
> +			mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x5000 0x1000>;
> +			clocks = <&mmsys CLK_MM_MDP_WROT0>;
> +			iommus = <&iommu M4U_PORT_MDP_WROT0>;
> +			mediatek,larb = <&larb0>;
> +		};
> +
> +		mdp_path0_sout@14005000 {
> +			compatible = "mediatek,mt8183-mdp-path";
> +			mediatek,mdp-id = <0>;
> +		};
> +
> +		mdp_wdma: mdp_wdma@14006000 {
> +			compatible = "mediatek,mt8183-mdp-wdma";
> +			mediatek,mdp-id = <0>;
> +			reg = <0 0x14006000 0 0x1000>;
> +			mediatek,gce-client-reg = <&gce SUBSYS_1400XXXX 0x6000 0x1000>;
> +			clocks = <&mmsys CLK_MM_MDP_WDMA0>;
> +			iommus = <&iommu M4U_PORT_MDP_WDMA0>;
> +			mediatek,larb = <&larb0>;
> +		};
> +
> +		mdp_path1_sout@14006000 {
> +			compatible = "mediatek,mt8183-mdp-path";
> +			mediatek,mdp-id = <1>;
> +		};
> +
> +		mdp_ccorr: mdp_ccorr@1401c000 {
> +			compatible = "mediatek,mt8183-mdp-ccorr";
> +			mediatek,mdp-id = <0>;
> +			reg = <0 0x1401c000 0 0x1000>;
> +			mediatek,gce-client-reg = <&gce SUBSYS_1401XXXX 0xc000 0x1000>;
> +			clocks = <&mmsys CLK_MM_MDP_CCORR>;
> +		};




_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH 1/4] arm64: Kconfig: Fix XGENE driver dependencies
From: Stephen Boyd @ 2019-09-12  1:03 UTC (permalink / raw)
  To: Amit Kucheria, Bartosz Golaszewski, Catalin Marinas,
	Kishon Vijay Abraham I, Liam Girdwood, Linus Walleij,
	Lorenzo Pieralisi, Mark Brown, Michael Turquette,
	Sebastian Reichel, Will Deacon, arm, linux-arm-kernel,
	linux-kernel
  Cc: linux-gpio, linux-pm, linux-clk, linux-pci
In-Reply-To: <f6cefef2bf6b34ec6eb82d3614054734fa5e8dd1.1568239378.git.amit.kucheria@linaro.org>

Quoting Amit Kucheria (2019-09-11 15:18:45)
> diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig
> index 801fa1cd0321..9b2790d3f18a 100644
> --- a/drivers/clk/Kconfig
> +++ b/drivers/clk/Kconfig
> @@ -225,7 +225,7 @@ config CLK_QORIQ
>  
>  config COMMON_CLK_XGENE
>         bool "Clock driver for APM XGene SoC"
> -       default ARCH_XGENE
> +       depends on ARCH_XGENE
>         depends on ARM64 || COMPILE_TEST

Is ARCH_XGENE supported outside of ARM64? I'd expect to see something
more like depends on ARCH_XGENE || COMPILE_TEST and default ARCH_XGENE
so that if the config is supported it becomes the default. Or at least
depends on ARCH_XGENE && ARM64 || COMPILE_TEST

>         ---help---
>           Sypport for the APM X-Gene SoC reference, PLL, and device clocks.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply

* Re: [PATCH net-next] net: stmmac: pci: Add HAPS support using GMAC5
From: David Miller @ 2019-09-11 22:50 UTC (permalink / raw)
  To: Jose.Abreu
  Cc: Joao.Pinto, alexandre.torgue, netdev, linux-kernel,
	mcoquelin.stm32, peppe.cavallaro, linux-stm32, linux-arm-kernel
In-Reply-To: <c37a55225e1ef66233b47c02b1441b91abeb3b76.1568047994.git.joabreu@synopsys.com>

From: Jose Abreu <Jose.Abreu@synopsys.com>
Date: Mon,  9 Sep 2019 18:54:26 +0200

> Add the support for Synopsys HAPS board that uses GMAC5.
> 
> Signed-off-by: Jose Abreu <joabreu@synopsys.com>

Applied.

_______________________________________________
linux-arm-kernel mailing list
linux-arm-kernel@lists.infradead.org
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

^ permalink raw reply


This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox