* [PATCH v27 1/9] memblock: add memblock_cap_memory_range()
From: AKASHI Takahiro @ 2016-11-17 5:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161116163015.GM7928@arm.com>
Will,
On Wed, Nov 16, 2016 at 04:30:15PM +0000, Will Deacon wrote:
> Hi Akashi,
>
> On Mon, Nov 14, 2016 at 02:55:16PM +0900, AKASHI Takahiro wrote:
> > On Fri, Nov 11, 2016 at 11:19:04AM +0800, Dennis Chen wrote:
> > > On Fri, Nov 11, 2016 at 11:50:50AM +0900, AKASHI Takahiro wrote:
> > > > On Thu, Nov 10, 2016 at 05:27:20PM +0000, Will Deacon wrote:
> > > > > On Wed, Nov 02, 2016 at 01:51:53PM +0900, AKASHI Takahiro wrote:
> > > > > > +void __init memblock_cap_memory_range(phys_addr_t base, phys_addr_t size)
> > > > > > +{
> > > > > > + int start_rgn, end_rgn;
> > > > > > + int i, ret;
> > > > > > +
> > > > > > + if (!size)
> > > > > > + return;
> > > > > > +
> > > > > > + ret = memblock_isolate_range(&memblock.memory, base, size,
> > > > > > + &start_rgn, &end_rgn);
> > > > > > + if (ret)
> > > > > > + return;
> > > > > > +
> > > > > > + /* remove all the MAP regions */
> > > > > > + for (i = memblock.memory.cnt - 1; i >= end_rgn; i--)
> > > > > > + if (!memblock_is_nomap(&memblock.memory.regions[i]))
> > > > > > + memblock_remove_region(&memblock.memory, i);
> > > > > > +
> > > > > > + for (i = start_rgn - 1; i >= 0; i--)
> > > > > > + if (!memblock_is_nomap(&memblock.memory.regions[i]))
> > > > > > + memblock_remove_region(&memblock.memory, i);
> > > > > > +
> > > > > > + /* truncate the reserved regions */
> > > > > > + memblock_remove_range(&memblock.reserved, 0, base);
> > > > > > + memblock_remove_range(&memblock.reserved,
> > > > > > + base + size, (phys_addr_t)ULLONG_MAX);
> > > > > > +}
> > > > >
> > > > > This duplicates a bunch of the logic in memblock_mem_limit_remove_map. Can
> > > > > you not implement that in terms of your new, more general, function? e.g.
> > > > > by passing base == 0, and size == limit?
> > > >
> > > > Obviously it's possible.
> > > > I actually talked to Dennis before about merging them,
> > > > but he was against my idea.
> > > >
> > > Oops! I thought we have reached agreement in the thread:http://lists.infradead.org/pipermail/linux-arm-kernel/2016-July/442817.html
> > > So feel free to do that as Will'll do
> >
> > OK, but I found that the two functions have a bit different semantics
> > in clipping memory range, in particular, when the range [base,base+size)
> > goes across several regions with a gap.
> > (This does not happen in my arm64 kdump, though.)
> > That is, 'limit' in memblock_mem_limit_remove_map() means total size of
> > available memory, while 'size' in memblock_cap_memory_range() indicates
> > the size of _continuous_ memory range.
>
> I thought limit was just a physical address, and then
No, it's not.
> memblock_mem_limit_remove_map operated on the end of the nearest memblock?
No, but "max_addr" returned by __find_max_addr() is a physical address
and the end address of memory of "limit" size in total.
> You could leave the __find_max_addr call in memblock_mem_limit_remove_map,
> given that I don't think you need/want it for memblock_cap_memory_range.
>
> > So I added an extra argument, exact, to a common function to specify
> > distinct behaviors. Confusing? Please see the patch below.
>
> Oh yikes, this certainly wasn't what I had in mind! My observation was
> just that memblock_mem_limit_remove_map(limit) does:
>
>
> 1. memblock_isolate_range(limit - limit+ULLONG_MAX)
> 2. memblock_remove_region(all non-nomap regions in the isolated region)
> 3. truncate reserved regions to limit
>
> and your memblock_cap_memory_range(base, size) does:
>
> 1. memblock_isolate_range(base - base+size)
> 2, memblock_remove_region(all non-nomap regions above and below the
> isolated region)
> 3. truncate reserved regions around the isolated region
>
> so, assuming we can invert the isolation in one of the cases, then they
> could share the same underlying implementation.
Please see my simplified patch below which would explain what I meant.
(Note that the size is calculated by 'max_addr - 0'.)
> I'm probably just missing something here, because the patch you've ended
> up with is far more involved than I anticipated...
I hope that it will meet almost your anticipation.
Thanks,
-Takahiro AKASHI
>
> Will
===8<===
diff --git a/mm/memblock.c b/mm/memblock.c
index 7608bc3..fea1688 100644
--- a/mm/memblock.c
+++ b/mm/memblock.c
@@ -1514,11 +1514,37 @@ void __init memblock_enforce_memory_limit(phys_addr_t limit)
(phys_addr_t)ULLONG_MAX);
}
+void __init memblock_cap_memory_range(phys_addr_t base, phys_addr_t size)
+{
+ int start_rgn, end_rgn;
+ int i, ret;
+
+ if (!size)
+ return;
+
+ ret = memblock_isolate_range(&memblock.memory, base, size,
+ &start_rgn, &end_rgn);
+ if (ret)
+ return;
+
+ /* remove all the MAP regions */
+ for (i = memblock.memory.cnt - 1; i >= end_rgn; i--)
+ if (!memblock_is_nomap(&memblock.memory.regions[i]))
+ memblock_remove_region(&memblock.memory, i);
+
+ for (i = start_rgn - 1; i >= 0; i--)
+ if (!memblock_is_nomap(&memblock.memory.regions[i]))
+ memblock_remove_region(&memblock.memory, i);
+
+ /* truncate the reserved regions */
+ memblock_remove_range(&memblock.reserved, 0, base);
+ memblock_remove_range(&memblock.reserved,
+ base + size, (phys_addr_t)ULLONG_MAX);
+}
+
void __init memblock_mem_limit_remove_map(phys_addr_t limit)
{
- struct memblock_type *type = &memblock.memory;
phys_addr_t max_addr;
- int i, ret, start_rgn, end_rgn;
if (!limit)
return;
@@ -1529,19 +1555,7 @@ void __init memblock_mem_limit_remove_map(phys_addr_t limit)
if (max_addr == (phys_addr_t)ULLONG_MAX)
return;
- ret = memblock_isolate_range(type, max_addr, (phys_addr_t)ULLONG_MAX,
- &start_rgn, &end_rgn);
- if (ret)
- return;
-
- /* remove all the MAP regions above the limit */
- for (i = end_rgn - 1; i >= start_rgn; i--) {
- if (!memblock_is_nomap(&type->regions[i]))
- memblock_remove_region(type, i);
- }
- /* truncate the reserved regions */
- memblock_remove_range(&memblock.reserved, max_addr,
- (phys_addr_t)ULLONG_MAX);
+ memblock_cap_memory_range(0, max_addr);
}
static int __init_memblock memblock_search(struct memblock_type *type, phys_addr_t addr)
^ permalink raw reply related
* [PATCH 1/1] drivers: dma-contiguous: Ensure cma reserve region never cross the low/high mem boundary
From: Jason Liu @ 2016-11-17 5:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <6bd1a1a9-2bc0-f5f4-0957-1826af15f4dd@redhat.com>
> -----Original Message-----
> From: Laura Abbott [mailto:labbott at redhat.com]
> Sent: Thursday, November 17, 2016 4:00 AM
> To: Jason Liu <jason.hui.liu@nxp.com>; linux-arm-kernel at lists.infradead.org
> Cc: gregkh at linuxfoundation.org; iamjoonsoo.kim at lge.com; linux-
> kernel at vger.kernel.org; m.szyprowski at samsung.com
> Subject: Re: [PATCH 1/1] drivers: dma-contiguous: Ensure cma reserve region
> never cross the low/high mem boundary
>
> On 11/16/2016 06:19 AM, Jason Liu wrote:
> > If the cma reserve region goes through the device-tree method, also
> > need ensure the cma reserved region not cross the low/high mem
> > boundary. This patch did the similar fix as commit:16195dd
> > ("mm: cma: Ensure that reservations never cross the low/high mem
> > boundary")
> >
> > Signed-off-by: Jason Liu <jason.hui.liu@nxp.com>
> > Cc: Marek Szyprowski <m.szyprowski@samsung.com>
> > Cc: Joonsoo Kim <iamjoonsoo.kim@lge.com>
> > Cc: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
> > ---
> > drivers/base/dma-contiguous.c | 27 +++++++++++++++++++++++++++
> > 1 file changed, 27 insertions(+)
> >
> > diff --git a/drivers/base/dma-contiguous.c
> > b/drivers/base/dma-contiguous.c index e167a1e1..2bc093c 100644
> > --- a/drivers/base/dma-contiguous.c
> > +++ b/drivers/base/dma-contiguous.c
> > @@ -244,6 +244,7 @@ static int __init rmem_cma_setup(struct
> > reserved_mem *rmem) {
> > phys_addr_t align = PAGE_SIZE << max(MAX_ORDER - 1,
> pageblock_order);
> > phys_addr_t mask = align - 1;
> > + phys_addr_t highmem_start;
> > unsigned long node = rmem->fdt_node;
> > struct cma *cma;
> > int err;
> > @@ -256,6 +257,32 @@ static int __init rmem_cma_setup(struct
> reserved_mem *rmem)
> > pr_err("Reserved memory: incorrect alignment of CMA
> region\n");
> > return -EINVAL;
> > }
> > +#ifdef CONFIG_X86
> > + /*
> > + * high_memory isn't direct mapped memory so retrieving its physical
> > + * address isn't appropriate. But it would be useful to check the
> > + * physical address of the highmem boundary so it's justfiable to get
> > + * the physical address from it. On x86 there is a validation check for
> > + * this case, so the following workaround is needed to avoid it.
> > + */
> > + highmem_start = __pa_nodebug(high_memory); #else
> > + highmem_start = __pa(high_memory);
> > +#endif
>
> The inline #ifdef is not great style, we shouldn't be spreading it around.
This is the similar fix in the 16195dd ("mm: cma: Ensure that reservations never cross
the low/high mem boundary". Do you have a better idea for this?
>
> > +
> > + /*
> > + * All pages in the reserved area must come from the same zone.
> > + * If the reserved region crosses the low/high memory boundary,
> > + * try to fix it up and then fall back to allocate from the low mem
> > + */
> > + if (rmem->base < highmem_start &&
> > + (rmem->base + rmem->size) > highmem_start) {
> > + memblock_free(rmem->base, rmem->size);
> > + rmem->base = memblock_alloc_range(rmem->size, align, 0,
> > + highmem_start,
> MEMBLOCK_NONE);
> > + if (!rmem->base)
> > + return -ENOMEM;
> > + }
>
> Given the alloc happened in the of code, it seems bad form to be bringing the
> free and re-alloc here. Perhaps we should be doing the limiting and checking in
> the reserved mem code?
I original though to fix it into the drivers/of/of_reserved_mem.c, but hesitate to
do it due to this of_reserved_mem is common code to do the reservation, which
is something not related with CMA requirement.
Appreciated that anyone can provide comments to improve this solution. Without this,
the Linux kernel will not boot up when do the CMA reservation from the DTS method,
since the dma_alloc_coherent will fail when do the dma memory allocation.
>
> If there is no other solution, at the least this deserves a pr_warn so users know
> why a reason specified may not be getting requested.
Yes, it deserves a pr_warn here. I will add it.
Thanks Laura for the review.
Jason Liu
>
> >
> > err = cma_init_reserved_mem(rmem->base, rmem->size, 0, &cma);
> > if (err) {
> >
>
>
> Thanks,
> Laura
^ permalink raw reply
* ILP32 for ARM64 - testing with lmbench
From: Maxim Kuvyrkov @ 2016-11-17 5:02 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <cdf5cdf2-43af-6d7f-9e0c-72675fb83224@huawei.com>
Hi Bamvor,
I'm surprised that you see this much difference from ILP32 patches on SPEC CPU2006int at all. The SPEC CPU2006 benchmarks spend almost no time in the kernel syscalls. I can imagine memory, TLB, and cache handling in the kernel could affect CPU2006 benchmarks. Do ILP32 patches touch code in those areas?
Other than that, it would be interesting to check what the variance is between the 3 iterations of benchmark runs. Could you check what relative standard deviation is between the 3 iterations -- (STDEV(RUN1, RUN2, RUN3) / RUNselected)?
For reference, in my [non-ILP32] benchmarking I see 1.1% for 401.bzip2, 0.8% for 429.mcf, 0.2% for 456.hmmer, and 0.1% for 462.libquantum.
--
Maxim Kuvyrkov
www.linaro.org
> On Nov 17, 2016, at 7:28 AM, Zhangjian (Bamvor) <bamvor.zhangjian@huawei.com> wrote:
>
> Hi, all
>
> I test specint of aarch64 LP64 when aarch32 el0 disable/enabled respectively
> and compare with ILP32 unmerged kernel(4.8-rc6) in our arm64 board. I found
> that difference(ILP32 disabled/ILP32 unmerged) is bigger when aarch32 el0 is
> enabled, compare with aarch32 el0 disabled kernel. And bzip2, mcg, hmmer,
> libquantum are the top four differences[1]. Note that bigger is better in
> specint test.
>
> In order to make sure the above results, I retest these four testcases in
> reportable way(reference the command in the end). The result[2] show that
> libquantum decrease -2.09% after ILP32 enabled and aarch32 on. I think it is in
> significant.
>
> The result of lmbench is not stable in my board. I plan to dig it later.
>
> [1] The following test result is tested through --size=ref --iterations=3.
> 1.1 Test when aarch32_el0 is enabled.
> ILP32 disabled base line
> 400.perlbench 100.00% 100%
> 401.bzip2 99.35% 100%
> 403.gcc 100.26% 100%
> 429.mcf 102.75% 100%
> 445.gobmk 100.00% 100%
> 456.hmmer 95.66% 100%
> 458.sjeng 100.00% 100%
> 462.libquantum 100.00% 100%
> 471.omnetpp 100.59% 100%
> 473.astar 99.66% 100%
> 483.xalancbmk 99.10% 100%
>
> 1.2 Test when aarch32_el0 is disabled
> ILP32 disabled base line
> 400.perlbench 100.22% 100%
> 401.bzip2 100.95% 100%
> 403.gcc 100.20% 100%
> 429.mcf 100.76% 100%
> 445.gobmk 100.36% 100%
> 456.hmmer 97.94% 100%
> 458.sjeng 99.73% 100%
> 462.libquantum 98.72% 100%
> 471.omnetpp 100.86% 100%
> 473.astar 99.15% 100%
> 483.xalancbmk 100.08% 100%
>
> [2] The following test result is tested through: runspec --config=my.cfg --size=test,train,ref --noreportable --tune=base,peak --iterations=3 bzip2 mcf hmmer libquantum
> 2.1 Test when aarch32_el0 is enabled.
> ILP32_enabled base line
> 401.bzip2 100.82% 100%
> 429.mcf 100.18% 100%
> 456.hmmer 99.64% 100%
> 462.libquantum 97.91% 100%
>
> Regards
>
> Bamvor
>
> On 2016/10/28 20:46, Yury Norov wrote:
>> [Add Steve Ellcey, thanks for testing on ThunderX]
>>
>> Lmbench-3.0-a9 testing is performed on ThunderX machine to check that
>> ILP32 series does not add performance regressions for LP64. Test
>> summary is in the table below. Our measurements doesn't show
>> significant performance regression of LP64 if ILP32 code is merged,
>> both enabled or disabled.
>>
>> ILP32 enabled ILP32 disabled Standard Kernel
>> null syscall 0.1066 0.1121 0.1121
>> 95.09% 100.00%
>>
>> stat 1.3947 1.3814 1.3864
>> 100.60% 99.64%
>>
>> fstat 0.4459 0.4344 0.4524
>> 98.56% 96.02%
>>
>> open/close 4.0606 4.0411 4.0453
>> 100.38% 99.90%
>>
>> read 0.4819 0.5014 0.5014
>> 96.11% 100.00%
>>
>> Tested with linux 4.8 because 4.9-rc1 is not fixed yet for ThunderX.
>> Other system details below.
>>
>> Yury.
>>
>> ubuntu at crb6:~$ uname -a
>> Linux crb6 4.8.0+ #3 SMP Thu Oct 27 11:01:32 PDT 2016 aarch64 aarch64 aarch64 GNU/Linux
>>
>> ubuntu at crb6:~$ cat /proc/meminfo
>> MemTotal: 132011948 kB
>> MemFree: 131442672 kB
>> MemAvailable: 130695764 kB
>> Buffers: 15696 kB
>> Cached: 88088 kB
>> SwapCached: 0 kB
>> Active: 82760 kB
>> Inactive: 41336 kB
>> Active(anon): 20880 kB
>> Inactive(anon): 8576 kB
>> Active(file): 61880 kB
>> Inactive(file): 32760 kB
>> Unevictable: 0 kB
>> Mlocked: 0 kB
>> SwapTotal: 128920572 kB
>> SwapFree: 128920572 kB
>> Dirty: 0 kB
>> Writeback: 0 kB
>> AnonPages: 20544 kB
>> Mapped: 19780 kB
>> Shmem: 9060 kB
>> Slab: 78804 kB
>> SReclaimable: 27372 kB
>> SUnreclaim: 51432 kB
>> KernelStack: 8336 kB
>> PageTables: 820 kB
>> NFS_Unstable: 0 kB
>> Bounce: 0 kB
>> WritebackTmp: 0 kB
>> CommitLimit: 194926544 kB
>> Committed_AS: 256324 kB
>> VmallocTotal: 135290290112 kB
>> VmallocUsed: 0 kB
>> VmallocChunk: 0 kB
>> AnonHugePages: 0 kB
>> ShmemHugePages: 0 kB
>> ShmemPmdMapped: 0 kB
>> CmaTotal: 0 kB
>> CmaFree: 0 kB
>> HugePages_Total: 0
>> HugePages_Free: 0
>> HugePages_Rsvd: 0
>> HugePages_Surp: 0
>> Hugepagesize: 2048 kB
>>
>> ubuntu at crb6:~$ cat /proc/cpuinfo
>> processor : 0
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 1
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 2
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 3
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 4
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 5
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 6
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 7
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 8
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 9
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 10
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 11
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 12
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 13
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 14
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 15
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 16
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 17
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 18
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 19
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 20
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 21
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 22
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 23
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 24
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 25
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 26
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 27
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 28
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 29
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 30
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 31
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 32
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 33
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 34
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 35
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 36
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 37
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 38
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 39
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 40
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 41
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 42
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 43
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 44
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 45
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 46
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>> processor : 47
>> BogoMIPS : 200.00
>> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
>> CPU implementer : 0x43
>> CPU architecture: 8
>> CPU variant : 0x1
>> CPU part : 0x0a1
>> CPU revision : 0
>>
>
^ permalink raw reply
* [PATCH 12/16] ARM: imx: use generic API for enabling SCU
From: pankaj.dubey @ 2016-11-17 4:29 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161114142631.GP3310@dragon>
Hi Shawn,
On Monday 14 November 2016 07:56 PM, Shawn Guo wrote:
> On Mon, Nov 14, 2016 at 10:32:07AM +0530, Pankaj Dubey wrote:
>> Now as we have of_scu_enable which takes care of mapping
>> scu base from DT, lets use it.
>>
>> At the same time this patch cleans up mach-imx platform files by
>> removing static mapping of SCU and dropping imx_scu_map_io function.
>
> I remember that the static mapping of SCU is necessary because SCU is
> being accessed at very early boot stage where dynamic mapping hasn't
> been set up.
>
>> CC: Shawn Guo <shawnguo@kernel.org>
>> CC: Sascha Hauer <kernel@pengutronix.de>
>> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
>> ---
>> arch/arm/mach-imx/common.h | 5 -----
>> arch/arm/mach-imx/mach-imx6q.c | 8 +-------
>> arch/arm/mach-imx/platsmp.c | 32 +++++---------------------------
>> arch/arm/mach-imx/pm-imx6.c | 3 ++-
>> 4 files changed, 8 insertions(+), 40 deletions(-)
>
> I tested it and saw that the booting of imx6q is broken like below.
Thanks for testing and letting me know about this.
Currently only two platforms (IMX and ZYNQ) are using SCU address at
very early stage of boot, for configuring possible cpus via
set_cpu_possible().. rest platforms are either using DT method or they
handle this in smp_prepare_cpus.
Since I am not sure if all boards based on IMX has been moved to DT
based boot, if it has moved to completely DT based then we do not need
this set_cpu_possible in smp_init_cpus, it will be taken care via
"arm_dt_init_cpu_maps" and this will avoid need of early mapping of SCU
base as well.
If not then, currently I can't see any other way to handle this and in
that case I will drop-out IMX platform's patch of using generic SCU APIs
in v2 version of series.
Thanks,
Pankaj Dubey
^ permalink raw reply
* [PATCH 01/16] ARM: scu: Provide support for parsing SCU device node to enable SCU
From: pankaj.dubey @ 2016-11-17 4:20 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161114145143.GM1041@n2100.armlinux.org.uk>
Hi Russell,
On Monday 14 November 2016 08:21 PM, Russell King - ARM Linux wrote:
> On Mon, Nov 14, 2016 at 03:37:44PM +0100, Arnd Bergmann wrote:
>> On Monday, November 14, 2016 1:50:18 PM CET Russell King - ARM Linux wrote:
>>> On Mon, Nov 14, 2016 at 01:03:09PM +0100, Arnd Bergmann wrote:
>>>> On Monday, November 14, 2016 2:10:16 PM CET pankaj.dubey wrote:
>>>>>>> + scu_base = of_iomap(np, 0);
>>>>>>> + of_node_put(np);
>>>>>>> + if (!scu_base) {
>>>>>>> + pr_err("%s failed to map scu_base via DT\n", __func__);
>>>>>>
>>>>>> For non-ca5, non-ca9 based SoCs, we'll see this error msg. We understand
>>>>>> what does it mean, but it may confuse normal users. In current version,
>>>>>> berlin doesn't complain like this for non-ca9 SoCs
>>>>>>
>>>>>
>>>>> OK, let me see other reviewer's comment on this. Then we will decide if
>>>>> this error message is required or can be omitted.
>>>>
>>>> We need to look at all callers here, to see if the function ever gets
>>>> called for a CPU that doesn't have an SCU. I'd say we should warn if
>>>> we know there is an SCU but we cannot map it, but never warn on
>>>> any of the CPU cores that don't support an SCU.
>>>
>>> Maybe there should be two helpers:
>>>
>>> of_scu_enable() which _only_ looks up the SCU address in DT and enables
>>> it if it finds it, otherwise returning failure.
>>>
>>> a9_scu_enable() which tries to use the A9 provided SCU address and
>>> enables it if it finds it, otherwise returning failure.
>>>
OK, In that case I can see need for following four helpers as:
1: of_scu_enable() which will __only__ lookup the SCU address in DT and
enables it if it finds, otherwise return -ENOMEM failure.
This helper APIs is required and sufficient for most of platforms such
as exynos, berlin, realview, socfpga, STi, ux500, vexpress, rockchip and
mvebu
2: a9_scu_enable(), which will __only__ use A9 provided SCU address and
enables it, if address mapped successfully, otherwise returning failure.
This helper APIs is required and sufficient for two ARM platforms as of
now tegra and hisi.
3: of_scu_get_base() which will lookup the SCU address in DT and if node
found maps address and returns ioremapped address to caller.
This helper APIs is required for three ARM plaforms rockchip, mvebu and
ux500, along with scu_enable() API to enable and find number_of_cores.
4: s9_scu_iomap_base() which will internally use s9_scu_get_base() and
do ioremap of scu address and returns ioremapped address to the caller
along with ownership (caller has responsibility to unmap it).
This helper APIs is required to simplify SCU enable and related code in
two ARM plaforms BCM ans ZX.
For remaining two ARM platforms (IMX and ZYNQ), none of these helpers
are useful for the time-being, as they need SCU mapping very early of
boot, where we can't use iomap APIs. So I will drop patches related to
these platforms in v2 version.
Please let me know if any concern in this approach.
>>> Then callers can decide which of these to call, and what error messages
>>> to print on their failures.
>>
>> Splitting the function in two is probably simpler overall, but
>> we may still have to look at all the callers: Any platform that
>> currently tries to map it on any CPU and doesn't warn about the
>> absence of the device node (or about scu_a9_has_base() == false)
>> should really continue not to warn about that.
>
> Did you miss the bit where none of of_scu_enable() or a9_scu_enable()
> should produce any warnings or errors to be printed. It's up to the
> caller to report the failure, otherwise doing this doesn't make sense:
>
> if (of_scu_enable() < 0 && a9_scu_enable() < 0)
> pr_err("Failed to map and enable the SCU\n");
>
> because if of_scu_enable() prints a warning/error, then it's patently
> misleading.
>
I will move out error message out of these helpers and let caller
(platform specific code) handle and print error if required.
Thanks,
Pankaj Dubey
^ permalink raw reply
* [PATCH v7 0/7] Add DRM driver for Hisilicon Hibmc
From: Rongrong Zou @ 2016-11-17 4:09 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOw6vbJHoELLTLpVjrfOZ8aEGzuDMFX5vWX8AxqNO35CT1iRxg@mail.gmail.com>
? 2016/11/17 0:02, Sean Paul ??:
> On Wed, Nov 16, 2016 at 11:01 AM, Sean Paul <seanpaul@chromium.org> wrote:
>> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>>> This patch set adds a new drm driver for Hisilicon Hibmc. Hibmc is a
>>> BMC SoC with a display controller intergrated, usually it is used on
>>> server for Out-of-band management purpose. In this patch set, we just
>>> support basic function for Hibmc display subsystem. Hibmc display
>>> subsystem is connected to host CPU by PCIe as blow:
>>>
>>> +----------+ +----------+
>>> | | PCIe | Hibmc |
>>> |host CPU( |<----->| display |
>>> |arm64,x86)| |subsystem |
>>> +----------+ +----------+
>>>
>>> Hardware Detail for Hibmc display subsystem
>>> -----------
>>>
>>> The display subsystem of Hibmc is show as bellow:
>>> +----+ +----+ +----+ +--------+
>>> | | | | | | | |
>>> | FB |----->| DE |----->|VDAC|---->|external|
>>> | | | | | | | VGA |
>>> +----+ +----+ +----+ +--------+
>>>
>>> -DE(Display Engine) is the display controller.
>>> -VDAC(Video Digital-to-Analog converter) converts the RGB diaital data
>>> stream from DE to VGA analog signals.
>>>
>>
>> For the whole series/driver:
>>
>> Acked-by: Sean Paul <seanpaul@chromium.org>
>>
>>
>
> Also, please send those fixups for the other ttm drivers ;)
with pleasure :)
Regards,
Rongrong.
>
>>
>>> Change History
>>> ------------
>>> Changes in v7:
>>> -remove hibmc_drm_power.c/hibmc_drm_power.h, move the functions to
>>> hibmc_drm_drv.c.
>>> -remove hibmc_drm_de.h and move the struct defined in head file to
>>> hibmc_drm_de.c.
>>> -plane is initialized inside crtc, not in hibmc_kms_init().
>>> -connector is initialized inside encoder, not in hibmc_kms_init().
>>> -remove plane/crtc/encoder/connector from hibmc_drm_private struct.
>>> -call drm_atomic_helper_suspend/resume in hibmc_pm_suspend/resume.
>>> -remove these empty stubs because caller will do NULL check.
>>> hibmc_plane_atomic_disable
>>> hibmc_crtc_atomic_check
>>> hibmc_encoder_disable
>>> hibmc_encoder_enable
>>> hibmc_encoder_atomic_check
>>> -clean up in all error paths of creating driver-private framebuffer.
>>>
>>> Changes in v6:
>>> -remove the embedded framebuffer and use a pointer of hibmc_framebuffer
>>> instead.
>>> -remove the deprecated drm_framebuffer_unregister_private(),
>>> drm_framebuffer_unreference() will be called in hibmc_fbdev_destroy().
>>> -uninstall irq in hibmc_unload().
>>>
>>> Changes in v5:
>>> -rebase on v4.9-rc2.
>>> -replace drm_fb_helper_set_suspend with drm_fb_helper_set_suspend_unlocked.
>>> and remove redundant console_lock and console_unlock.
>>>
>>> Changes in v4:
>>> -remove unused include files, and include header file when it is needed.
>>> -remove unused FLAG in Kconfig: DRM_GEM_CMA_HELPER/DRM_KMS_CMA_HELPER.
>>> -remove drm_helper_disable_unused_functions, since we use DRIVER_ATOMIC.
>>>
>>> Changes in v3:
>>> -enable KMS, in v2, only fbdev is enabled.
>>> -management video memory with ttm.
>>> -add vblank interrupt.
>>> -remove drm_connector_register_all() and drm_connector_unregister_all().
>>> -I have a basic test with igt.
>>>
>>> Changes in v2:
>>> -Remove self-defined macros for bit operations.
>>> -Remove unused register.
>>> -Replace those deprecated functions with new version of them.
>>> -use drm_connector_register_all() to register connector after
>>> drm_dev_register().
>>>
>>> The patch v2 is at
>>> https://lists.freedesktop.org/archives/dri-devel/2016-May/108661.html
>>>
>>> Rongrong Zou (7):
>>> drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
>>> drm/hisilicon/hibmc: Add video memory management
>>> drm/hisilicon/hibmc: Add support for frame buffer
>>> drm/hisilicon/hibmc: Add support for display engine
>>> drm/hisilicon/hibmc: Add support for VDAC
>>> drm/hisilicon/hibmc: Add support for vblank interrupt
>>> MAINTAINERS: Update HISILICON DRM entries
>>>
>>> MAINTAINERS | 1 +
>>> drivers/gpu/drm/hisilicon/Kconfig | 1 +
>>> drivers/gpu/drm/hisilicon/Makefile | 1 +
>>> drivers/gpu/drm/hisilicon/hibmc/Kconfig | 9 +
>>> drivers/gpu/drm/hisilicon/hibmc/Makefile | 4 +
>>> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c | 477 ++++++++++++++++++
>>> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 456 ++++++++++++++++++
>>> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 114 +++++
>>> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c | 267 +++++++++++
>>> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 ++++++++
>>> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c | 147 ++++++
>>> drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c | 558 ++++++++++++++++++++++
>>> 12 files changed, 2231 insertions(+)
>>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_de.c
>>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_fbdev.c
>>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_vdac.c
>>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_ttm.c
>>>
>>> --
>>> 1.9.1
>>>
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>
--
Regards, Rongrong
^ permalink raw reply
* [PATCH v7 1/7] drm/hisilicon/hibmc: Add hisilicon hibmc drm master driver
From: Rongrong Zou @ 2016-11-17 4:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOw6vb+w3-qr+KFMYikVzVvS1n35sZPZFd8_8BRPCOgqVsGa8Q@mail.gmail.com>
Hi Sean,
Thanks for reviewing.
? 2016/11/16 23:42, Sean Paul ??:
> On Wed, Nov 16, 2016 at 8:43 AM, Rongrong Zou <zourongrong@gmail.com> wrote:
>> Add DRM master driver for Hisilicon Hibmc SoC which used for
>> Out-of-band management. Blow is the general hardware connection,
>> both the Hibmc and the host CPU are on the same mother board.
>>
>> +----------+ +----------+
>> | | PCIe | Hibmc |
>> |host CPU( |<----->| display |
>> |arm64,x86)| |subsystem |
>> +----------+ +----------+
>>
>> Signed-off-by: Rongrong Zou <zourongrong@gmail.com>
>> ---
>
> In the future, please keep track of the differences between patch
> versions. I noticed you have a short changelog in the cover letter,
> but it really helps to add one per-patch as well, it makes reviewing
> much simpler.
>
> Reviewed-by: Sean Paul <seanpaul@chromium.org>
Sorry for that, I will pay attention to it later, thanks.
Regards,
Rongrong.
>
>
>> drivers/gpu/drm/hisilicon/Kconfig | 1 +
>> drivers/gpu/drm/hisilicon/Makefile | 1 +
>> drivers/gpu/drm/hisilicon/hibmc/Kconfig | 9 +
>> drivers/gpu/drm/hisilicon/hibmc/Makefile | 4 +
>> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c | 308 +++++++++++++++++++++++
>> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h | 41 +++
>> drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h | 196 +++++++++++++++
>> 7 files changed, 560 insertions(+)
>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/Makefile
>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> create mode 100644 drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>>
>> diff --git a/drivers/gpu/drm/hisilicon/Kconfig b/drivers/gpu/drm/hisilicon/Kconfig
>> index 558c61b..2fd2724 100644
>> --- a/drivers/gpu/drm/hisilicon/Kconfig
>> +++ b/drivers/gpu/drm/hisilicon/Kconfig
>> @@ -2,4 +2,5 @@
>> # hisilicon drm device configuration.
>> # Please keep this list sorted alphabetically
>>
>> +source "drivers/gpu/drm/hisilicon/hibmc/Kconfig"
>> source "drivers/gpu/drm/hisilicon/kirin/Kconfig"
>> diff --git a/drivers/gpu/drm/hisilicon/Makefile b/drivers/gpu/drm/hisilicon/Makefile
>> index e3f6d49..c8155bf 100644
>> --- a/drivers/gpu/drm/hisilicon/Makefile
>> +++ b/drivers/gpu/drm/hisilicon/Makefile
>> @@ -2,4 +2,5 @@
>> # Makefile for hisilicon drm drivers.
>> # Please keep this list sorted alphabetically
>>
>> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc/
>> obj-$(CONFIG_DRM_HISI_KIRIN) += kirin/
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Kconfig b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> new file mode 100644
>> index 0000000..380622a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Kconfig
>> @@ -0,0 +1,9 @@
>> +config DRM_HISI_HIBMC
>> + tristate "DRM Support for Hisilicon Hibmc"
>> + depends on DRM && PCI
>> + select DRM_KMS_HELPER
>> + select DRM_TTM
>> +
>> + help
>> + Choose this option if you have a Hisilicon Hibmc soc chipset.
>> + If M is selected the module will be called hibmc-drm.
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/Makefile b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> new file mode 100644
>> index 0000000..47962a0
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/Makefile
>> @@ -0,0 +1,4 @@
>> +ccflags-y := -Iinclude/drm
>> +hibmc-drm-y := hibmc_drm_drv.o
>> +
>> +obj-$(CONFIG_DRM_HISI_HIBMC) += hibmc-drm.o
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> new file mode 100644
>> index 0000000..6d20580
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.c
>> @@ -0,0 +1,308 @@
>> +/* Hisilicon Hibmc SoC drm driver
>> + *
>> + * Based on the bochs drm driver.
>> + *
>> + * Copyright (c) 2016 Huawei Limited.
>> + *
>> + * Author:
>> + * Rongrong Zou <zourongrong@huawei.com>
>> + * Rongrong Zou <zourongrong@gmail.com>
>> + * Jianhua Li <lijianhua@huawei.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + */
>> +
>> +#include <linux/console.h>
>> +#include <linux/module.h>
>> +
>> +#include "hibmc_drm_drv.h"
>> +#include "hibmc_drm_regs.h"
>> +
>> +static const struct file_operations hibmc_fops = {
>> + .owner = THIS_MODULE,
>> + .open = drm_open,
>> + .release = drm_release,
>> + .unlocked_ioctl = drm_ioctl,
>> + .compat_ioctl = drm_compat_ioctl,
>> + .poll = drm_poll,
>> + .read = drm_read,
>> + .llseek = no_llseek,
>> +};
>> +
>> +static int hibmc_enable_vblank(struct drm_device *dev, unsigned int pipe)
>> +{
>> + return 0;
>> +}
>> +
>> +static void hibmc_disable_vblank(struct drm_device *dev, unsigned int pipe)
>> +{
>> +}
>> +
>> +static struct drm_driver hibmc_driver = {
>> + .fops = &hibmc_fops,
>> + .name = "hibmc",
>> + .date = "20160828",
>> + .desc = "hibmc drm driver",
>> + .major = 1,
>> + .minor = 0,
>> + .get_vblank_counter = drm_vblank_no_hw_counter,
>> + .enable_vblank = hibmc_enable_vblank,
>> + .disable_vblank = hibmc_disable_vblank,
>> +};
>> +
>> +static int hibmc_pm_suspend(struct device *dev)
>> +{
>> + return 0;
>> +}
>> +
>> +static int hibmc_pm_resume(struct device *dev)
>> +{
>> + return 0;
>> +}
>> +
>> +static const struct dev_pm_ops hibmc_pm_ops = {
>> + SET_SYSTEM_SLEEP_PM_OPS(hibmc_pm_suspend,
>> + hibmc_pm_resume)
>> +};
>> +
>> +/*
>> + * It can operate in one of three modes: 0, 1 or Sleep.
>> + */
>> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>> + unsigned int power_mode)
>> +{
>> + unsigned int control_value = 0;
>> + void __iomem *mmio = priv->mmio;
>> + unsigned int input = 1;
>> +
>> + if (power_mode > HIBMC_PW_MODE_CTL_MODE_SLEEP)
>> + return;
>> +
>> + if (power_mode == HIBMC_PW_MODE_CTL_MODE_SLEEP)
>> + input = 0;
>> +
>> + control_value = readl(mmio + HIBMC_POWER_MODE_CTRL);
>> + control_value &= ~(HIBMC_PW_MODE_CTL_MODE_MASK |
>> + HIBMC_PW_MODE_CTL_OSC_INPUT_MASK);
>> + control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_MODE, power_mode);
>> + control_value |= HIBMC_FIELD(HIBMC_PW_MODE_CTL_OSC_INPUT, input);
>> + writel(control_value, mmio + HIBMC_POWER_MODE_CTRL);
>> +}
>> +
>> +void hibmc_set_current_gate(struct hibmc_drm_private *priv, unsigned int gate)
>> +{
>> + unsigned int gate_reg;
>> + unsigned int mode;
>> + void __iomem *mmio = priv->mmio;
>> +
>> + /* Get current power mode. */
>> + mode = (readl(mmio + HIBMC_POWER_MODE_CTRL) &
>> + HIBMC_PW_MODE_CTL_MODE_MASK) >> HIBMC_PW_MODE_CTL_MODE_SHIFT;
>> +
>> + switch (mode) {
>> + case HIBMC_PW_MODE_CTL_MODE_MODE0:
>> + gate_reg = HIBMC_MODE0_GATE;
>> + break;
>> +
>> + case HIBMC_PW_MODE_CTL_MODE_MODE1:
>> + gate_reg = HIBMC_MODE1_GATE;
>> + break;
>> +
>> + default:
>> + gate_reg = HIBMC_MODE0_GATE;
>> + break;
>> + }
>> + writel(gate, mmio + gate_reg);
>> +}
>> +
>> +static void hibmc_hw_config(struct hibmc_drm_private *priv)
>> +{
>> + unsigned int reg;
>> +
>> + /* On hardware reset, power mode 0 is default. */
>> + hibmc_set_power_mode(priv, HIBMC_PW_MODE_CTL_MODE_MODE0);
>> +
>> + /* Enable display power gate & LOCALMEM power gate*/
>> + reg = readl(priv->mmio + HIBMC_CURRENT_GATE);
>> + reg &= ~HIBMC_CURR_GATE_DISPLAY_MASK;
>> + reg &= ~HIBMC_CURR_GATE_LOCALMEM_MASK;
>> + reg |= HIBMC_CURR_GATE_DISPLAY(1);
>> + reg |= HIBMC_CURR_GATE_LOCALMEM(1);
>> +
>> + hibmc_set_current_gate(priv, reg);
>> +
>> + /*
>> + * Reset the memory controller. If the memory controller
>> + * is not reset in chip,the system might hang when sw accesses
>> + * the memory.The memory should be resetted after
>> + * changing the MXCLK.
>> + */
>> + reg = readl(priv->mmio + HIBMC_MISC_CTRL);
>> + reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> + reg |= HIBMC_MSCCTL_LOCALMEM_RESET(0);
>> + writel(reg, priv->mmio + HIBMC_MISC_CTRL);
>> +
>> + reg &= ~HIBMC_MSCCTL_LOCALMEM_RESET_MASK;
>> + reg |= HIBMC_MSCCTL_LOCALMEM_RESET(1);
>> +
>> + writel(reg, priv->mmio + HIBMC_MISC_CTRL);
>> +}
>> +
>> +static int hibmc_hw_map(struct hibmc_drm_private *priv)
>> +{
>> + struct drm_device *dev = priv->dev;
>> + struct pci_dev *pdev = dev->pdev;
>> + resource_size_t addr, size, ioaddr, iosize;
>> +
>> + ioaddr = pci_resource_start(pdev, 1);
>> + iosize = pci_resource_len(pdev, 1);
>> + priv->mmio = devm_ioremap_nocache(dev->dev, ioaddr, iosize);
>> + if (!priv->mmio) {
>> + DRM_ERROR("Cannot map mmio region\n");
>> + return -ENOMEM;
>> + }
>> +
>> + addr = pci_resource_start(pdev, 0);
>> + size = pci_resource_len(pdev, 0);
>> + priv->fb_map = devm_ioremap(dev->dev, addr, size);
>> + if (!priv->fb_map) {
>> + DRM_ERROR("Cannot map framebuffer\n");
>> + return -ENOMEM;
>> + }
>> + priv->fb_base = addr;
>> + priv->fb_size = size;
>> +
>> + return 0;
>> +}
>> +
>> +static int hibmc_hw_init(struct hibmc_drm_private *priv)
>> +{
>> + int ret;
>> +
>> + ret = hibmc_hw_map(priv);
>> + if (ret)
>> + return ret;
>> +
>> + hibmc_hw_config(priv);
>> +
>> + return 0;
>> +}
>> +
>> +static int hibmc_unload(struct drm_device *dev)
>> +{
>> + return 0;
>> +}
>> +
>> +static int hibmc_load(struct drm_device *dev)
>> +{
>> + struct hibmc_drm_private *priv;
>> + int ret;
>> +
>> + priv = devm_kzalloc(dev->dev, sizeof(*priv), GFP_KERNEL);
>> + if (!priv) {
>> + DRM_ERROR("no memory to allocate for hibmc_drm_private\n");
>> + return -ENOMEM;
>> + }
>> + dev->dev_private = priv;
>> + priv->dev = dev;
>> +
>> + ret = hibmc_hw_init(priv);
>> + if (ret)
>> + goto err;
>> +
>> + return 0;
>> +
>> +err:
>> + hibmc_unload(dev);
>> + DRM_ERROR("failed to initialize drm driver: %d\n", ret);
>> + return ret;
>> +}
>> +
>> +static int hibmc_pci_probe(struct pci_dev *pdev,
>> + const struct pci_device_id *ent)
>> +{
>> + struct drm_device *dev;
>> + int ret;
>> +
>> + dev = drm_dev_alloc(&hibmc_driver, &pdev->dev);
>> + if (!dev) {
>> + DRM_ERROR("failed to allocate drm_device\n");
>> + return -ENOMEM;
>> + }
>> +
>> + dev->pdev = pdev;
>> + pci_set_drvdata(pdev, dev);
>> +
>> + ret = pci_enable_device(pdev);
>> + if (ret) {
>> + DRM_ERROR("failed to enable pci device: %d\n", ret);
>> + goto err_free;
>> + }
>> +
>> + ret = hibmc_load(dev);
>> + if (ret) {
>> + DRM_ERROR("failed to load hibmc: %d\n", ret);
>> + goto err_disable;
>> + }
>> +
>> + ret = drm_dev_register(dev, 0);
>> + if (ret) {
>> + DRM_ERROR("failed to register drv for userspace access: %d\n",
>> + ret);
>> + goto err_unload;
>> + }
>> + return 0;
>> +
>> +err_unload:
>> + hibmc_unload(dev);
>> +err_disable:
>> + pci_disable_device(pdev);
>> +err_free:
>> + drm_dev_unref(dev);
>> +
>> + return ret;
>> +}
>> +
>> +static void hibmc_pci_remove(struct pci_dev *pdev)
>> +{
>> + struct drm_device *dev = pci_get_drvdata(pdev);
>> +
>> + drm_dev_unregister(dev);
>> + hibmc_unload(dev);
>> + drm_dev_unref(dev);
>> +}
>> +
>> +static struct pci_device_id hibmc_pci_table[] = {
>> + {0x19e5, 0x1711, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
>> + {0,}
>> +};
>> +
>> +static struct pci_driver hibmc_pci_driver = {
>> + .name = "hibmc-drm",
>> + .id_table = hibmc_pci_table,
>> + .probe = hibmc_pci_probe,
>> + .remove = hibmc_pci_remove,
>> + .driver.pm = &hibmc_pm_ops,
>> +};
>> +
>> +static int __init hibmc_init(void)
>> +{
>> + return pci_register_driver(&hibmc_pci_driver);
>> +}
>> +
>> +static void __exit hibmc_exit(void)
>> +{
>> + return pci_unregister_driver(&hibmc_pci_driver);
>> +}
>> +
>> +module_init(hibmc_init);
>> +module_exit(hibmc_exit);
>> +
>> +MODULE_DEVICE_TABLE(pci, hibmc_pci_table);
>> +MODULE_AUTHOR("RongrongZou <zourongrong@huawei.com>");
>> +MODULE_DESCRIPTION("DRM Driver for Hisilicon Hibmc");
>> +MODULE_LICENSE("GPL v2");
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> new file mode 100644
>> index 0000000..840cd5a
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_drv.h
>> @@ -0,0 +1,41 @@
>> +/* Hisilicon Hibmc SoC drm driver
>> + *
>> + * Based on the bochs drm driver.
>> + *
>> + * Copyright (c) 2016 Huawei Limited.
>> + *
>> + * Author:
>> + * Rongrong Zou <zourongrong@huawei.com>
>> + * Rongrong Zou <zourongrong@gmail.com>
>> + * Jianhua Li <lijianhua@huawei.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + */
>> +
>> +#ifndef HIBMC_DRM_DRV_H
>> +#define HIBMC_DRM_DRV_H
>> +
>> +#include <drm/drmP.h>
>> +
>> +struct hibmc_drm_private {
>> + /* hw */
>> + void __iomem *mmio;
>> + void __iomem *fb_map;
>> + unsigned long fb_base;
>> + unsigned long fb_size;
>> +
>> + /* drm */
>> + struct drm_device *dev;
>> +
>> +};
>> +
>> +void hibmc_set_power_mode(struct hibmc_drm_private *priv,
>> + unsigned int power_mode);
>> +void hibmc_set_current_gate(struct hibmc_drm_private *priv,
>> + unsigned int gate);
>> +
>> +#endif
>> diff --git a/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>> new file mode 100644
>> index 0000000..f7035bf
>> --- /dev/null
>> +++ b/drivers/gpu/drm/hisilicon/hibmc/hibmc_drm_regs.h
>> @@ -0,0 +1,196 @@
>> +/* Hisilicon Hibmc SoC drm driver
>> + *
>> + * Based on the bochs drm driver.
>> + *
>> + * Copyright (c) 2016 Huawei Limited.
>> + *
>> + * Author:
>> + * Rongrong Zou <zourongrong@huawei.com>
>> + * Rongrong Zou <zourongrong@gmail.com>
>> + * Jianhua Li <lijianhua@huawei.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify
>> + * it under the terms of the GNU General Public License as published by
>> + * the Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + */
>> +
>> +#ifndef HIBMC_DRM_HW_H
>> +#define HIBMC_DRM_HW_H
>> +
>> +/* register definition */
>> +#define HIBMC_MISC_CTRL 0x4
>> +
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET(x) ((x) << 6)
>> +#define HIBMC_MSCCTL_LOCALMEM_RESET_MASK 0x40
>> +
>> +#define HIBMC_CURRENT_GATE 0x000040
>> +#define HIBMC_CURR_GATE_DISPLAY(x) ((x) << 2)
>> +#define HIBMC_CURR_GATE_DISPLAY_MASK 0x4
>> +
>> +#define HIBMC_CURR_GATE_LOCALMEM(x) ((x) << 1)
>> +#define HIBMC_CURR_GATE_LOCALMEM_MASK 0x2
>> +
>> +#define HIBMC_MODE0_GATE 0x000044
>> +#define HIBMC_MODE1_GATE 0x000048
>> +#define HIBMC_POWER_MODE_CTRL 0x00004C
>> +
>> +#define HIBMC_PW_MODE_CTL_OSC_INPUT(x) ((x) << 3)
>> +#define HIBMC_PW_MODE_CTL_OSC_INPUT_MASK 0x8
>> +
>> +#define HIBMC_PW_MODE_CTL_MODE(x) ((x) << 0)
>> +#define HIBMC_PW_MODE_CTL_MODE_MASK 0x03
>> +#define HIBMC_PW_MODE_CTL_MODE_SHIFT 0
>> +
>> +#define HIBMC_PW_MODE_CTL_MODE_MODE0 0
>> +#define HIBMC_PW_MODE_CTL_MODE_MODE1 1
>> +#define HIBMC_PW_MODE_CTL_MODE_SLEEP 2
>> +
>> +#define HIBMC_PANEL_PLL_CTRL 0x00005C
>> +#define HIBMC_CRT_PLL_CTRL 0x000060
>> +
>> +#define HIBMC_PLL_CTRL_BYPASS(x) ((x) << 18)
>> +#define HIBMC_PLL_CTRL_BYPASS_MASK 0x40000
>> +
>> +#define HIBMC_PLL_CTRL_POWER(x) ((x) << 17)
>> +#define HIBMC_PLL_CTRL_POWER_MASK 0x20000
>> +
>> +#define HIBMC_PLL_CTRL_INPUT(x) ((x) << 16)
>> +#define HIBMC_PLL_CTRL_INPUT_MASK 0x10000
>> +
>> +#define HIBMC_PLL_CTRL_POD(x) ((x) << 14)
>> +#define HIBMC_PLL_CTRL_POD_MASK 0xC000
>> +
>> +#define HIBMC_PLL_CTRL_OD(x) ((x) << 12)
>> +#define HIBMC_PLL_CTRL_OD_MASK 0x3000
>> +
>> +#define HIBMC_PLL_CTRL_N(x) ((x) << 8)
>> +#define HIBMC_PLL_CTRL_N_MASK 0xF00
>> +
>> +#define HIBMC_PLL_CTRL_M(x) ((x) << 0)
>> +#define HIBMC_PLL_CTRL_M_MASK 0xFF
>> +
>> +#define HIBMC_CRT_DISP_CTL 0x80200
>> +
>> +#define HIBMC_CRT_DISP_CTL_CRTSELECT(x) ((x) << 25)
>> +#define HIBMC_CRT_DISP_CTL_CRTSELECT_MASK 0x2000000
>> +
>> +#define HIBMC_CRTSELECT_CRT 1
>> +
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE(x) ((x) << 14)
>> +#define HIBMC_CRT_DISP_CTL_CLOCK_PHASE_MASK 0x4000
>> +
>> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE(x) ((x) << 13)
>> +#define HIBMC_CRT_DISP_CTL_VSYNC_PHASE_MASK 0x2000
>> +
>> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE(x) ((x) << 12)
>> +#define HIBMC_CRT_DISP_CTL_HSYNC_PHASE_MASK 0x1000
>> +
>> +#define HIBMC_CRT_DISP_CTL_TIMING(x) ((x) << 8)
>> +#define HIBMC_CRT_DISP_CTL_TIMING_MASK 0x100
>> +
>> +#define HIBMC_CRT_DISP_CTL_PLANE(x) ((x) << 2)
>> +#define HIBMC_CRT_DISP_CTL_PLANE_MASK 4
>> +
>> +#define HIBMC_CRT_DISP_CTL_FORMAT(x) ((x) << 0)
>> +#define HIBMC_CRT_DISP_CTL_FORMAT_MASK 0x03
>> +
>> +#define HIBMC_CRT_FB_ADDRESS 0x080204
>> +
>> +#define HIBMC_CRT_FB_WIDTH 0x080208
>> +#define HIBMC_CRT_FB_WIDTH_WIDTH(x) ((x) << 16)
>> +#define HIBMC_CRT_FB_WIDTH_WIDTH_MASK 0x3FFF0000
>> +#define HIBMC_CRT_FB_WIDTH_OFFS(x) ((x) << 0)
>> +#define HIBMC_CRT_FB_WIDTH_OFFS_MASK 0x3FFF
>> +
>> +#define HIBMC_CRT_HORZ_TOTAL 0x08020C
>> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL(x) ((x) << 16)
>> +#define HIBMC_CRT_HORZ_TOTAL_TOTAL_MASK 0xFFF0000
>> +
>> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END(x) ((x) << 0)
>> +#define HIBMC_CRT_HORZ_TOTAL_DISP_END_MASK 0xFFF
>> +
>> +#define HIBMC_CRT_HORZ_SYNC 0x080210
>> +#define HIBMC_CRT_HORZ_SYNC_WIDTH(x) ((x) << 16)
>> +#define HIBMC_CRT_HORZ_SYNC_WIDTH_MASK 0xFF0000
>> +
>> +#define HIBMC_CRT_HORZ_SYNC_START(x) ((x) << 0)
>> +#define HIBMC_CRT_HORZ_SYNC_START_MASK 0xFFF
>> +
>> +#define HIBMC_CRT_VERT_TOTAL 0x080214
>> +#define HIBMC_CRT_VERT_TOTAL_TOTAL(x) ((x) << 16)
>> +#define HIBMC_CRT_VERT_TOTAL_TOTAL_MASK 0x7FFF0000
>> +
>> +#define HIBMC_CRT_VERT_TOTAL_DISP_END(x) ((x) << 0)
>> +#define HIBMC_CRT_VERT_TOTAL_DISP_END_MASK 0x7FF
>> +
>> +#define HIBMC_CRT_VERT_SYNC 0x080218
>> +#define HIBMC_CRT_VERT_SYNC_HEIGHT(x) ((x) << 16)
>> +#define HIBMC_CRT_VERT_SYNC_HEIGHT_MASK 0x3F0000
>> +
>> +#define HIBMC_CRT_VERT_SYNC_START(x) ((x) << 0)
>> +#define HIBMC_CRT_VERT_SYNC_START_MASK 0x7FF
>> +
>> +/* Auto Centering */
>> +#define HIBMC_CRT_AUTO_CENTERING_TL 0x080280
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP(x) ((x) << 16)
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_TOP_MASK 0x7FF0000
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT(x) ((x) << 0)
>> +#define HIBMC_CRT_AUTO_CENTERING_TL_LEFT_MASK 0x7FF
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_BR 0x080284
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM(x) ((x) << 16)
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_BOTTOM_MASK 0x7FF0000
>> +
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT(x) ((x) << 0)
>> +#define HIBMC_CRT_AUTO_CENTERING_BR_RIGHT_MASK 0x7FF
>> +
>> +/* register to control panel output */
>> +#define HIBMC_DISPLAY_CONTROL_HISILE 0x80288
>> +#define HIBMC_DISPLAY_CONTROL_FPVDDEN(x) ((x) << 0)
>> +#define HIBMC_DISPLAY_CONTROL_PANELDATE(x) ((x) << 1)
>> +#define HIBMC_DISPLAY_CONTROL_FPEN(x) ((x) << 2)
>> +#define HIBMC_DISPLAY_CONTROL_VBIASEN(x) ((x) << 3)
>> +
>> +#define HIBMC_RAW_INTERRUPT 0x80290
>> +#define HIBMC_RAW_INTERRUPT_VBLANK(x) ((x) << 2)
>> +#define HIBMC_RAW_INTERRUPT_VBLANK_MASK 0x4
>> +
>> +#define HIBMC_RAW_INTERRUPT_EN 0x80298
>> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK(x) ((x) << 2)
>> +#define HIBMC_RAW_INTERRUPT_EN_VBLANK_MASK 0x4
>> +
>> +/* register and values for PLL control */
>> +#define CRT_PLL1_HS 0x802a8
>> +#define CRT_PLL1_HS_OUTER_BYPASS(x) ((x) << 30)
>> +#define CRT_PLL1_HS_INTER_BYPASS(x) ((x) << 29)
>> +#define CRT_PLL1_HS_POWERON(x) ((x) << 24)
>> +
>> +#define CRT_PLL1_HS_25MHZ 0x23d40f02
>> +#define CRT_PLL1_HS_40MHZ 0x23940801
>> +#define CRT_PLL1_HS_65MHZ 0x23940d01
>> +#define CRT_PLL1_HS_78MHZ 0x23540F82
>> +#define CRT_PLL1_HS_74MHZ 0x23941dc2
>> +#define CRT_PLL1_HS_80MHZ 0x23941001
>> +#define CRT_PLL1_HS_80MHZ_1152 0x23540fc2
>> +#define CRT_PLL1_HS_108MHZ 0x23b41b01
>> +#define CRT_PLL1_HS_162MHZ 0x23480681
>> +#define CRT_PLL1_HS_148MHZ 0x23541dc2
>> +#define CRT_PLL1_HS_193MHZ 0x234807c1
>> +
>> +#define CRT_PLL2_HS 0x802ac
>> +#define CRT_PLL2_HS_25MHZ 0x206B851E
>> +#define CRT_PLL2_HS_40MHZ 0x30000000
>> +#define CRT_PLL2_HS_65MHZ 0x40000000
>> +#define CRT_PLL2_HS_78MHZ 0x50E147AE
>> +#define CRT_PLL2_HS_74MHZ 0x602B6AE7
>> +#define CRT_PLL2_HS_80MHZ 0x70000000
>> +#define CRT_PLL2_HS_108MHZ 0x80000000
>> +#define CRT_PLL2_HS_162MHZ 0xA0000000
>> +#define CRT_PLL2_HS_148MHZ 0xB0CCCCCD
>> +#define CRT_PLL2_HS_193MHZ 0xC0872B02
>> +
>> +#define HIBMC_FIELD(field, value) (field(value) & field##_MASK)
>> +#endif
>> --
>> 1.9.1
>>
> _______________________________________________
> linuxarm mailing list
> linuxarm at huawei.com
> http://rnd-openeuler.huawei.com/mailman/listinfo/linuxarm
>
> .
>
^ permalink raw reply
* [PATCH v1 2/4] mailbox: Add iProc mailbox controller driver
From: Jassi Brar @ 2016-11-17 3:40 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476817238-1226-3-git-send-email-jonathan.richardson@broadcom.com>
Hi Jonathan,
On Wed, Oct 19, 2016 at 12:30 AM, Jonathan Richardson
<jonathan.richardson@broadcom.com> wrote:
> The Broadcom iProc mailbox controller handles all communication with a
> Cortex-M0 MCU processor that provides support for power, clock, and
> reset management.
>
> Tested-by: Jonathan Richardson <jonathan.richardson@broadcom.com>
> Reviewed-by: Jonathan Richardson <jonathan.richardson@broadcom.com>
> Reviewed-by: Vikram Prakash <vikram.prakash@broadcom.com>
> Reviewed-by: Shreesha Rajashekar <shreesha.rajashekar@broadcom.com>
> Reviewed-by: Ray Jui <ray.jui@broadcom.com>
> Reviewed-by: Scott Branden <scott.branden@broadcom.com>
> Signed-off-by: Jonathan Richardson <jonathan.richardson@broadcom.com>
> ---
> drivers/mailbox/Kconfig | 10 +
> drivers/mailbox/Makefile | 2 +
> drivers/mailbox/bcm-iproc-mailbox.c | 422 ++++++++++++++++++++++++++++++++++++
> include/linux/bcm_iproc_mailbox.h | 32 +++
>
This should be include/linux/mailbox/bcm_iproc_mailbox.h
> +++ b/drivers/mailbox/bcm-iproc-mailbox.c
> @@ -0,0 +1,422 @@
> +/*
> + * Copyright (C) 2016 Broadcom.
> + *
> + * This program is free software; you can redistribute it and/or
> + * modify it under the terms of the GNU General Public License as
> + * published by the Free Software Foundation version 2.
> + *
> + * This program is distributed "as is" WITHOUT ANY WARRANTY of any
> + * kind, whether express or implied; without even the implied warranty
> + * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +#include <linux/kernel.h>
> +#include <linux/slab.h>
> +#include <linux/module.h>
> +#include <linux/irq.h>
> +#include <linux/interrupt.h>
> +#include <linux/io.h>
> +#include <linux/platform_device.h>
> +#include <linux/of_device.h>
> +#include <linux/of.h>
> +#include <linux/of_irq.h>
> +#include <linux/irqchip/chained_irq.h>
> +#include <linux/notifier.h>
> +#include <linux/reboot.h>
> +#include <linux/mailbox_controller.h>
> +#include <linux/mailbox_client.h>
>
Need of mailbox_controller.h & client.h is a bad sign.
> +
> +static int iproc_mbox_send_data_m0_imp(struct iproc_mbox *mbox,
> + struct iproc_mbox_msg *msg, int max_retries, int poll_period_us)
> +{
> + unsigned long flags;
> + u32 val;
> + int err = 0;
> + int retries;
> +
> + spin_lock_irqsave(&mbox->lock, flags);
> +
> + dev_dbg(mbox->dev, "Send msg to M0: cmd=0x%x, param=0x%x, wait_ack=%d\n",
> + msg->cmd, msg->param, msg->wait_ack);
> +
> + writel(msg->cmd, mbox->base + IPROC_CRMU_MAILBOX0_OFFSET);
> + writel(msg->param, mbox->base + IPROC_CRMU_MAILBOX1_OFFSET);
> +
> + if (msg->wait_ack) {
> + err = msg->reply_code = -ETIMEDOUT;
> + for (retries = 0; retries < max_retries; retries++) {
> + val = readl(mbox->base + IPROC_CRMU_MAILBOX0_OFFSET);
> + if (val & M0_IPC_CMD_DONE_MASK) {
> + /*
> + * M0 replied - save reply code and
> + * clear error.
> + */
> + msg->reply_code = (val &
> + M0_IPC_CMD_REPLY_MASK) >>
> + M0_IPC_CMD_REPLY_SHIFT;
> + err = 0;
> + break;
> + }
> + udelay(poll_period_us);
> + }
> + }
> +
> + spin_unlock_irqrestore(&mbox->lock, flags);
> +
> + return err;
> +}
> +
OK, so this is the real message passing voodoo.
> +static void iproc_mbox_aon_gpio_forwarding_enable(struct iproc_mbox *mbox,
> + bool en)
> +{
> + struct iproc_mbox_msg msg;
> + const int max_retries = 5;
> + const int poll_period_us = 200;
> +
> + msg.cmd = M0_IPC_M0_CMD_AON_GPIO_FORWARDING_ENABLE;
> + msg.param = en ? 1 : 0;
> + msg.wait_ack = true;
> +
> + iproc_mbox_send_data_m0_imp(mbox, &msg, max_retries, poll_period_us);
> +}
> +
> +static void iproc_mbox_irq_unmask(struct irq_data *d)
> +{
> + struct iproc_mbox *iproc_mbox = irq_data_get_irq_chip_data(d);
> +
> + iproc_mbox_aon_gpio_forwarding_enable(iproc_mbox, true);
> +}
> +
> +static void iproc_mbox_irq_mask(struct irq_data *d)
> +{
> + /* Do nothing - Mask callback is not required, since upon GPIO event,
> + * M0 disables GPIO forwarding to A9. Hence, GPIO forwarding is already
> + * disabled when in mbox irq handler, and no other mbox events from M0
> + * to A9 are expected until GPIO forwarding is enabled following
> + * iproc_mbox_irq_unmask()
> + */
> +}
> +
> +static struct irq_chip iproc_mbox_irq_chip = {
> + .name = "bcm-iproc-mbox",
> + .irq_mask = iproc_mbox_irq_mask,
> + .irq_unmask = iproc_mbox_irq_unmask,
> +};
> +
.... these are simply using the mailbox controllers directly. So you
are actually clubbing a mailbox client (interrupt controller) with the
provider (mailbox) here.
I think you need move the IRQ controller part under drivers/irqchip/
that uses the mailbox api to manage its 'irq lines'.
Thanks.
^ permalink raw reply
* [PATCH v6 3/3] arm: dts: mt2701: Add node for Mediatek JPEG Decoder
From: Rick Chang @ 2016-11-17 3:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479353915-5043-1-git-send-email-rick.chang@mediatek.com>
Signed-off-by: Rick Chang <rick.chang@mediatek.com>
Signed-off-by: Minghsiu Tsai <minghsiu.tsai@mediatek.com>
---
This patch depends on:
CCF "Add clock support for Mediatek MT2701"[1]
iommu and smi "Add the dtsi node of iommu and smi for mt2701"[2]
[1] http://lists.infradead.org/pipermail/linux-mediatek/2016-October/007271.html
[2] https://patchwork.kernel.org/patch/9164013/
---
arch/arm/boot/dts/mt2701.dtsi | 14 ++++++++++++++
1 file changed, 14 insertions(+)
diff --git a/arch/arm/boot/dts/mt2701.dtsi b/arch/arm/boot/dts/mt2701.dtsi
index 8f13c70..4dd5048 100644
--- a/arch/arm/boot/dts/mt2701.dtsi
+++ b/arch/arm/boot/dts/mt2701.dtsi
@@ -298,6 +298,20 @@
power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
};
+ jpegdec: jpegdec at 15004000 {
+ compatible = "mediatek,mt2701-jpgdec";
+ reg = <0 0x15004000 0 0x1000>;
+ interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&imgsys CLK_IMG_JPGDEC_SMI>,
+ <&imgsys CLK_IMG_JPGDEC>;
+ clock-names = "jpgdec-smi",
+ "jpgdec";
+ power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
+ mediatek,larb = <&larb2>;
+ iommus = <&iommu MT2701_M4U_PORT_JPGDEC_WDMA>,
+ <&iommu MT2701_M4U_PORT_JPGDEC_BSDMA>;
+ };
+
vdecsys: syscon at 16000000 {
compatible = "mediatek,mt2701-vdecsys", "syscon";
reg = <0 0x16000000 0 0x1000>;
--
1.9.1
^ permalink raw reply related
* [PATCH v6 2/3] vcodec: mediatek: Add Mediatek JPEG Decoder Driver
From: Rick Chang @ 2016-11-17 3:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479353915-5043-1-git-send-email-rick.chang@mediatek.com>
Add v4l2 driver for Mediatek JPEG Decoder
Signed-off-by: Rick Chang <rick.chang@mediatek.com>
Signed-off-by: Minghsiu Tsai <minghsiu.tsai@mediatek.com>
---
drivers/media/platform/Kconfig | 15 +
drivers/media/platform/Makefile | 2 +
drivers/media/platform/mtk-jpeg/Makefile | 2 +
drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 1303 ++++++++++++++++++++++
drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h | 139 +++
drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c | 417 +++++++
drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h | 91 ++
drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c | 160 +++
drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h | 25 +
drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h | 58 +
10 files changed, 2212 insertions(+)
create mode 100644 drivers/media/platform/mtk-jpeg/Makefile
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h
diff --git a/drivers/media/platform/Kconfig b/drivers/media/platform/Kconfig
index 754edbf1..96c9887 100644
--- a/drivers/media/platform/Kconfig
+++ b/drivers/media/platform/Kconfig
@@ -162,6 +162,21 @@ config VIDEO_CODA
Coda is a range of video codec IPs that supports
H.264, MPEG-4, and other video formats.
+config VIDEO_MEDIATEK_JPEG
+ tristate "Mediatek JPEG Codec driver"
+ depends on MTK_IOMMU_V1 || COMPILE_TEST
+ depends on VIDEO_DEV && VIDEO_V4L2
+ depends on ARCH_MEDIATEK || COMPILE_TEST
+ depends on HAS_DMA
+ select VIDEOBUF2_DMA_CONTIG
+ select V4L2_MEM2MEM_DEV
+ ---help---
+ Mediatek jpeg codec driver provides HW capability to decode
+ JPEG format
+
+ To compile this driver as a module, choose M here: the
+ module will be called mtk-jpeg
+
config VIDEO_MEDIATEK_VPU
tristate "Mediatek Video Processor Unit"
depends on VIDEO_DEV && VIDEO_V4L2 && HAS_DMA
diff --git a/drivers/media/platform/Makefile b/drivers/media/platform/Makefile
index f842933..cf701e3 100644
--- a/drivers/media/platform/Makefile
+++ b/drivers/media/platform/Makefile
@@ -68,3 +68,5 @@ obj-$(CONFIG_VIDEO_MEDIATEK_VPU) += mtk-vpu/
obj-$(CONFIG_VIDEO_MEDIATEK_VCODEC) += mtk-vcodec/
obj-$(CONFIG_VIDEO_MEDIATEK_MDP) += mtk-mdp/
+
+obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk-jpeg/
diff --git a/drivers/media/platform/mtk-jpeg/Makefile b/drivers/media/platform/mtk-jpeg/Makefile
new file mode 100644
index 0000000..b2e6069
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/Makefile
@@ -0,0 +1,2 @@
+mtk_jpeg-objs := mtk_jpeg_core.o mtk_jpeg_hw.o mtk_jpeg_parse.o
+obj-$(CONFIG_VIDEO_MEDIATEK_JPEG) += mtk_jpeg.o
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
new file mode 100644
index 0000000..1101da8
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
@@ -0,0 +1,1303 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ * Rick Chang <rick.chang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/clk.h>
+#include <linux/err.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/spinlock.h>
+#include <media/v4l2-event.h>
+#include <media/v4l2-mem2mem.h>
+#include <media/v4l2-ioctl.h>
+#include <media/videobuf2-core.h>
+#include <media/videobuf2-dma-contig.h>
+#include <soc/mediatek/smi.h>
+#include <asm/dma-iommu.h>
+
+#include "mtk_jpeg_hw.h"
+#include "mtk_jpeg_core.h"
+#include "mtk_jpeg_parse.h"
+
+static struct mtk_jpeg_fmt mtk_jpeg_formats[] = {
+ {
+ .fourcc = V4L2_PIX_FMT_JPEG,
+ .colplanes = 1,
+ .flags = MTK_JPEG_FMT_FLAG_DEC_OUTPUT,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV420M,
+ .h_sample = {4, 2, 2},
+ .v_sample = {4, 2, 2},
+ .colplanes = 3,
+ .h_align = 5,
+ .v_align = 4,
+ .flags = MTK_JPEG_FMT_FLAG_DEC_CAPTURE,
+ },
+ {
+ .fourcc = V4L2_PIX_FMT_YUV422M,
+ .h_sample = {4, 2, 2},
+ .v_sample = {4, 4, 4},
+ .colplanes = 3,
+ .h_align = 5,
+ .v_align = 3,
+ .flags = MTK_JPEG_FMT_FLAG_DEC_CAPTURE,
+ },
+};
+
+#define MTK_JPEG_NUM_FORMATS ARRAY_SIZE(mtk_jpeg_formats)
+
+enum {
+ MTK_JPEG_BUF_FLAGS_INIT = 0,
+ MTK_JPEG_BUF_FLAGS_LAST_FRAME = 1,
+};
+
+struct mtk_jpeg_src_buf {
+ struct vb2_v4l2_buffer b;
+ struct list_head list;
+ int flags;
+ struct mtk_jpeg_dec_param dec_param;
+};
+
+static int debug;
+module_param(debug, int, 0644);
+
+static inline struct mtk_jpeg_ctx *mtk_jpeg_fh_to_ctx(struct v4l2_fh *fh)
+{
+ return container_of(fh, struct mtk_jpeg_ctx, fh);
+}
+
+static inline struct mtk_jpeg_src_buf *mtk_jpeg_vb2_to_srcbuf(
+ struct vb2_buffer *vb)
+{
+ return container_of(to_vb2_v4l2_buffer(vb), struct mtk_jpeg_src_buf, b);
+}
+
+static int mtk_jpeg_querycap(struct file *file, void *priv,
+ struct v4l2_capability *cap)
+{
+ struct mtk_jpeg_dev *jpeg = video_drvdata(file);
+
+ strlcpy(cap->driver, MTK_JPEG_NAME " decoder", sizeof(cap->driver));
+ strlcpy(cap->card, MTK_JPEG_NAME " decoder", sizeof(cap->card));
+ snprintf(cap->bus_info, sizeof(cap->bus_info), "platform:%s",
+ dev_name(jpeg->dev));
+
+ return 0;
+}
+
+static int mtk_jpeg_enum_fmt(struct mtk_jpeg_fmt *mtk_jpeg_formats, int n,
+ struct v4l2_fmtdesc *f, u32 type)
+{
+ int i, num = 0;
+
+ for (i = 0; i < n; ++i) {
+ if (mtk_jpeg_formats[i].flags & type) {
+ if (num == f->index)
+ break;
+ ++num;
+ }
+ }
+
+ if (i >= n)
+ return -EINVAL;
+
+ f->pixelformat = mtk_jpeg_formats[i].fourcc;
+
+ return 0;
+}
+
+static int mtk_jpeg_enum_fmt_vid_cap(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f,
+ MTK_JPEG_FMT_FLAG_DEC_CAPTURE);
+}
+
+static int mtk_jpeg_enum_fmt_vid_out(struct file *file, void *priv,
+ struct v4l2_fmtdesc *f)
+{
+ return mtk_jpeg_enum_fmt(mtk_jpeg_formats, MTK_JPEG_NUM_FORMATS, f,
+ MTK_JPEG_FMT_FLAG_DEC_OUTPUT);
+}
+
+static struct mtk_jpeg_q_data *mtk_jpeg_get_q_data(struct mtk_jpeg_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ if (V4L2_TYPE_IS_OUTPUT(type))
+ return &ctx->out_q;
+ return &ctx->cap_q;
+}
+
+static struct mtk_jpeg_fmt *mtk_jpeg_find_format(struct mtk_jpeg_ctx *ctx,
+ u32 pixelformat,
+ unsigned int fmt_type)
+{
+ unsigned int k, fmt_flag;
+
+ fmt_flag = (fmt_type == MTK_JPEG_FMT_TYPE_OUTPUT) ?
+ MTK_JPEG_FMT_FLAG_DEC_OUTPUT :
+ MTK_JPEG_FMT_FLAG_DEC_CAPTURE;
+
+ for (k = 0; k < MTK_JPEG_NUM_FORMATS; k++) {
+ struct mtk_jpeg_fmt *fmt = &mtk_jpeg_formats[k];
+
+ if (fmt->fourcc == pixelformat && fmt->flags & fmt_flag)
+ return fmt;
+ }
+
+ return NULL;
+}
+
+static void mtk_jpeg_bound_align_image(u32 *w, unsigned int wmin,
+ unsigned int wmax, unsigned int walign,
+ u32 *h, unsigned int hmin,
+ unsigned int hmax, unsigned int halign)
+{
+ int width, height, w_step, h_step;
+
+ width = *w;
+ height = *h;
+ w_step = 1 << walign;
+ h_step = 1 << halign;
+
+ v4l_bound_align_image(w, wmin, wmax, walign, h, hmin, hmax, halign, 0);
+ if (*w < width && (*w + w_step) <= wmax)
+ *w += w_step;
+ if (*h < height && (*h + h_step) <= hmax)
+ *h += h_step;
+}
+
+static void mtk_jpeg_adjust_fmt_mplane(struct mtk_jpeg_ctx *ctx,
+ struct v4l2_format *f)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct mtk_jpeg_q_data *q_data;
+ int i;
+
+ q_data = mtk_jpeg_get_q_data(ctx, f->type);
+
+ pix_mp->width = q_data->w;
+ pix_mp->height = q_data->h;
+ pix_mp->pixelformat = q_data->fmt->fourcc;
+ pix_mp->num_planes = q_data->fmt->colplanes;
+
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ pix_mp->plane_fmt[i].bytesperline = q_data->bytesperline[i];
+ pix_mp->plane_fmt[i].sizeimage = q_data->sizeimage[i];
+ }
+}
+
+static int mtk_jpeg_try_fmt_mplane(struct v4l2_format *f,
+ struct mtk_jpeg_fmt *fmt,
+ struct mtk_jpeg_ctx *ctx, int q_type)
+{
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ int i;
+
+ memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+ pix_mp->field = V4L2_FIELD_NONE;
+
+ if (ctx->state != MTK_JPEG_INIT) {
+ mtk_jpeg_adjust_fmt_mplane(ctx, f);
+ goto end;
+ }
+
+ pix_mp->num_planes = fmt->colplanes;
+ pix_mp->pixelformat = fmt->fourcc;
+
+ if (q_type == MTK_JPEG_FMT_TYPE_OUTPUT) {
+ struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[0];
+
+ mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH,
+ MTK_JPEG_MAX_WIDTH, 0,
+ &pix_mp->height, MTK_JPEG_MIN_HEIGHT,
+ MTK_JPEG_MAX_HEIGHT, 0);
+
+ memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+ pfmt->bytesperline = 0;
+ /* Source size must be aligned to 128 */
+ pfmt->sizeimage = mtk_jpeg_align(pfmt->sizeimage, 128);
+ if (pfmt->sizeimage == 0)
+ pfmt->sizeimage = MTK_JPEG_DEFAULT_SIZEIMAGE;
+ goto end;
+ }
+
+ /* type is MTK_JPEG_FMT_TYPE_CAPTURE */
+ mtk_jpeg_bound_align_image(&pix_mp->width, MTK_JPEG_MIN_WIDTH,
+ MTK_JPEG_MAX_WIDTH, fmt->h_align,
+ &pix_mp->height, MTK_JPEG_MIN_HEIGHT,
+ MTK_JPEG_MAX_HEIGHT, fmt->v_align);
+
+ for (i = 0; i < fmt->colplanes; i++) {
+ struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i];
+ u32 stride = pix_mp->width * fmt->h_sample[i] / 4;
+ u32 h = pix_mp->height * fmt->v_sample[i] / 4;
+
+ memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+ pfmt->bytesperline = stride;
+ pfmt->sizeimage = stride * h;
+ }
+end:
+ v4l2_dbg(2, debug, &jpeg->v4l2_dev, "wxh:%ux%u\n",
+ pix_mp->width, pix_mp->height);
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ v4l2_dbg(2, debug, &jpeg->v4l2_dev,
+ "plane[%d] bpl=%u, size=%u\n",
+ i,
+ pix_mp->plane_fmt[i].bytesperline,
+ pix_mp->plane_fmt[i].sizeimage);
+ }
+ return 0;
+}
+
+static int mtk_jpeg_g_fmt_vid_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct mtk_jpeg_q_data *q_data = NULL;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ int i;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = mtk_jpeg_get_q_data(ctx, f->type);
+
+ memset(pix_mp->reserved, 0, sizeof(pix_mp->reserved));
+ pix_mp->width = q_data->w;
+ pix_mp->height = q_data->h;
+ pix_mp->field = V4L2_FIELD_NONE;
+ pix_mp->pixelformat = q_data->fmt->fourcc;
+ pix_mp->num_planes = q_data->fmt->colplanes;
+ pix_mp->colorspace = ctx->colorspace;
+ pix_mp->ycbcr_enc = ctx->ycbcr_enc;
+ pix_mp->xfer_func = ctx->xfer_func;
+ pix_mp->quantization = ctx->quantization;
+
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) g_fmt:%c%c%c%c wxh:%ux%u\n",
+ f->type,
+ (pix_mp->pixelformat & 0xff),
+ (pix_mp->pixelformat >> 8 & 0xff),
+ (pix_mp->pixelformat >> 16 & 0xff),
+ (pix_mp->pixelformat >> 24 & 0xff),
+ pix_mp->width, pix_mp->height);
+
+ for (i = 0; i < pix_mp->num_planes; i++) {
+ struct v4l2_plane_pix_format *pfmt = &pix_mp->plane_fmt[i];
+
+ pfmt->bytesperline = q_data->bytesperline[i];
+ pfmt->sizeimage = q_data->sizeimage[i];
+ memset(pfmt->reserved, 0, sizeof(pfmt->reserved));
+
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev,
+ "plane[%d] bpl=%u, size=%u\n",
+ i,
+ pfmt->bytesperline,
+ pfmt->sizeimage);
+ }
+ return 0;
+}
+
+static int mtk_jpeg_try_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+ struct mtk_jpeg_fmt *fmt;
+
+ fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
+ MTK_JPEG_FMT_TYPE_CAPTURE);
+ if (!fmt)
+ fmt = ctx->cap_q.fmt;
+
+ v4l2_dbg(2, debug, &ctx->jpeg->v4l2_dev, "(%d) try_fmt:%c%c%c%c\n",
+ f->type,
+ (fmt->fourcc & 0xff),
+ (fmt->fourcc >> 8 & 0xff),
+ (fmt->fourcc >> 16 & 0xff),
+ (fmt->fourcc >> 24 & 0xff));
+
+ return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_CAPTURE);
+}
+
+static int mtk_jpeg_try_fmt_vid_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+ struct mtk_jpeg_fmt *fmt;
+
+ fmt = mtk_jpeg_find_format(ctx, f->fmt.pix_mp.pixelformat,
+ MTK_JPEG_FMT_TYPE_OUTPUT);
+ if (!fmt)
+ fmt = ctx->out_q.fmt;
+
+ v4l2_dbg(2, debug, &ctx->jpeg->v4l2_dev, "(%d) try_fmt:%c%c%c%c\n",
+ f->type,
+ (fmt->fourcc & 0xff),
+ (fmt->fourcc >> 8 & 0xff),
+ (fmt->fourcc >> 16 & 0xff),
+ (fmt->fourcc >> 24 & 0xff));
+
+ return mtk_jpeg_try_fmt_mplane(f, fmt, ctx, MTK_JPEG_FMT_TYPE_OUTPUT);
+}
+
+static int mtk_jpeg_s_fmt_mplane(struct mtk_jpeg_ctx *ctx,
+ struct v4l2_format *f)
+{
+ struct vb2_queue *vq;
+ struct mtk_jpeg_q_data *q_data = NULL;
+ struct v4l2_pix_format_mplane *pix_mp = &f->fmt.pix_mp;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ unsigned int f_type;
+ int i;
+
+ vq = v4l2_m2m_get_vq(ctx->fh.m2m_ctx, f->type);
+ if (!vq)
+ return -EINVAL;
+
+ q_data = mtk_jpeg_get_q_data(ctx, f->type);
+
+ if (vb2_is_busy(vq)) {
+ v4l2_err(&jpeg->v4l2_dev, "queue busy\n");
+ return -EBUSY;
+ }
+
+ f_type = V4L2_TYPE_IS_OUTPUT(f->type) ?
+ MTK_JPEG_FMT_TYPE_OUTPUT : MTK_JPEG_FMT_TYPE_CAPTURE;
+
+ q_data->fmt = mtk_jpeg_find_format(ctx, pix_mp->pixelformat, f_type);
+ q_data->w = pix_mp->width;
+ q_data->h = pix_mp->height;
+ ctx->colorspace = pix_mp->colorspace;
+ ctx->ycbcr_enc = pix_mp->ycbcr_enc;
+ ctx->xfer_func = pix_mp->xfer_func;
+ ctx->quantization = pix_mp->quantization;
+
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) s_fmt:%c%c%c%c wxh:%ux%u\n",
+ f->type,
+ (q_data->fmt->fourcc & 0xff),
+ (q_data->fmt->fourcc >> 8 & 0xff),
+ (q_data->fmt->fourcc >> 16 & 0xff),
+ (q_data->fmt->fourcc >> 24 & 0xff),
+ q_data->w, q_data->h);
+
+ for (i = 0; i < q_data->fmt->colplanes; i++) {
+ q_data->bytesperline[i] = pix_mp->plane_fmt[i].bytesperline;
+ q_data->sizeimage[i] = pix_mp->plane_fmt[i].sizeimage;
+
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev,
+ "plane[%d] bpl=%u, size=%u\n",
+ i, q_data->bytesperline[i], q_data->sizeimage[i]);
+ }
+
+ return 0;
+}
+
+static int mtk_jpeg_s_fmt_vid_out_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = mtk_jpeg_try_fmt_vid_out_mplane(file, priv, f);
+ if (ret)
+ return ret;
+
+ return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f);
+}
+
+static int mtk_jpeg_s_fmt_vid_cap_mplane(struct file *file, void *priv,
+ struct v4l2_format *f)
+{
+ int ret;
+
+ ret = mtk_jpeg_try_fmt_vid_cap_mplane(file, priv, f);
+ if (ret)
+ return ret;
+
+ return mtk_jpeg_s_fmt_mplane(mtk_jpeg_fh_to_ctx(priv), f);
+}
+
+static void mtk_jpeg_queue_src_chg_event(struct mtk_jpeg_ctx *ctx)
+{
+ static const struct v4l2_event ev_src_ch = {
+ .type = V4L2_EVENT_SOURCE_CHANGE,
+ .u.src_change.changes =
+ V4L2_EVENT_SRC_CH_RESOLUTION,
+ };
+
+ v4l2_event_queue_fh(&ctx->fh, &ev_src_ch);
+}
+
+static int mtk_jpeg_subscribe_event(struct v4l2_fh *fh,
+ const struct v4l2_event_subscription *sub)
+{
+ switch (sub->type) {
+ case V4L2_EVENT_SOURCE_CHANGE:
+ return v4l2_src_change_event_subscribe(fh, sub);
+ default:
+ return -EINVAL;
+ }
+}
+
+static int mtk_jpeg_g_selection(struct file *file, void *priv,
+ struct v4l2_selection *s)
+{
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE:
+ case V4L2_SEL_TGT_COMPOSE_DEFAULT:
+ s->r.width = ctx->out_q.w;
+ s->r.height = ctx->out_q.h;
+ s->r.left = 0;
+ s->r.top = 0;
+ break;
+ case V4L2_SEL_TGT_COMPOSE_BOUNDS:
+ case V4L2_SEL_TGT_COMPOSE_PADDED:
+ s->r.width = ctx->cap_q.w;
+ s->r.height = ctx->cap_q.h;
+ s->r.left = 0;
+ s->r.top = 0;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int mtk_jpeg_s_selection(struct file *file, void *priv,
+ struct v4l2_selection *s)
+{
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+
+ if (s->type != V4L2_BUF_TYPE_VIDEO_CAPTURE)
+ return -EINVAL;
+
+ switch (s->target) {
+ case V4L2_SEL_TGT_COMPOSE:
+ s->r.left = 0;
+ s->r.top = 0;
+ s->r.width = ctx->out_q.w;
+ s->r.height = ctx->out_q.h;
+ break;
+ default:
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static int mtk_jpeg_qbuf(struct file *file, void *priv, struct v4l2_buffer *buf)
+{
+ struct v4l2_fh *fh = file->private_data;
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(priv);
+ struct vb2_queue *vq;
+ struct vb2_buffer *vb;
+ struct mtk_jpeg_src_buf *jpeg_src_buf;
+
+ if (buf->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ goto end;
+
+ vq = v4l2_m2m_get_vq(fh->m2m_ctx, buf->type);
+ if (buf->index >= vq->num_buffers) {
+ dev_err(ctx->jpeg->dev, "buffer index out of range\n");
+ return -EINVAL;
+ }
+
+ vb = vq->bufs[buf->index];
+ jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
+ jpeg_src_buf->flags = (buf->m.planes[0].bytesused == 0) ?
+ MTK_JPEG_BUF_FLAGS_LAST_FRAME : MTK_JPEG_BUF_FLAGS_INIT;
+end:
+ return v4l2_m2m_qbuf(file, fh->m2m_ctx, buf);
+}
+
+static const struct v4l2_ioctl_ops mtk_jpeg_ioctl_ops = {
+ .vidioc_querycap = mtk_jpeg_querycap,
+ .vidioc_enum_fmt_vid_cap_mplane = mtk_jpeg_enum_fmt_vid_cap,
+ .vidioc_enum_fmt_vid_out_mplane = mtk_jpeg_enum_fmt_vid_out,
+ .vidioc_try_fmt_vid_cap_mplane = mtk_jpeg_try_fmt_vid_cap_mplane,
+ .vidioc_try_fmt_vid_out_mplane = mtk_jpeg_try_fmt_vid_out_mplane,
+ .vidioc_g_fmt_vid_cap_mplane = mtk_jpeg_g_fmt_vid_mplane,
+ .vidioc_g_fmt_vid_out_mplane = mtk_jpeg_g_fmt_vid_mplane,
+ .vidioc_s_fmt_vid_cap_mplane = mtk_jpeg_s_fmt_vid_cap_mplane,
+ .vidioc_s_fmt_vid_out_mplane = mtk_jpeg_s_fmt_vid_out_mplane,
+ .vidioc_qbuf = mtk_jpeg_qbuf,
+ .vidioc_subscribe_event = mtk_jpeg_subscribe_event,
+ .vidioc_g_selection = mtk_jpeg_g_selection,
+ .vidioc_s_selection = mtk_jpeg_s_selection,
+
+ .vidioc_create_bufs = v4l2_m2m_ioctl_create_bufs,
+ .vidioc_prepare_buf = v4l2_m2m_ioctl_prepare_buf,
+ .vidioc_reqbufs = v4l2_m2m_ioctl_reqbufs,
+ .vidioc_querybuf = v4l2_m2m_ioctl_querybuf,
+ .vidioc_dqbuf = v4l2_m2m_ioctl_dqbuf,
+ .vidioc_expbuf = v4l2_m2m_ioctl_expbuf,
+ .vidioc_streamon = v4l2_m2m_ioctl_streamon,
+ .vidioc_streamoff = v4l2_m2m_ioctl_streamoff,
+
+ .vidioc_unsubscribe_event = v4l2_event_unsubscribe,
+};
+
+static int mtk_jpeg_queue_setup(struct vb2_queue *q,
+ unsigned int *num_buffers,
+ unsigned int *num_planes,
+ unsigned int sizes[],
+ struct device *alloc_ctxs[])
+{
+ struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+ struct mtk_jpeg_q_data *q_data = NULL;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ int i;
+
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev, "(%d) buf_req count=%u\n",
+ q->type, *num_buffers);
+
+ q_data = mtk_jpeg_get_q_data(ctx, q->type);
+ if (!q_data)
+ return -EINVAL;
+
+ *num_planes = q_data->fmt->colplanes;
+ for (i = 0; i < q_data->fmt->colplanes; i++) {
+ sizes[i] = q_data->sizeimage[i];
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev, "sizeimage[%d]=%u\n",
+ i, sizes[i]);
+ }
+
+ return 0;
+}
+
+static int mtk_jpeg_buf_prepare(struct vb2_buffer *vb)
+{
+ struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct mtk_jpeg_q_data *q_data = NULL;
+ int i;
+
+ q_data = mtk_jpeg_get_q_data(ctx, vb->vb2_queue->type);
+ if (!q_data)
+ return -EINVAL;
+
+ for (i = 0; i < q_data->fmt->colplanes; i++)
+ vb2_set_plane_payload(vb, i, q_data->sizeimage[i]);
+
+ return 0;
+}
+
+static bool mtk_jpeg_check_resolution_change(struct mtk_jpeg_ctx *ctx,
+ struct mtk_jpeg_dec_param *param)
+{
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ struct mtk_jpeg_q_data *q_data;
+
+ q_data = &ctx->out_q;
+ if (q_data->w != param->pic_w || q_data->h != param->pic_h) {
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Picture size change\n");
+ return true;
+ }
+
+ q_data = &ctx->cap_q;
+ if (q_data->fmt != mtk_jpeg_find_format(ctx, param->dst_fourcc,
+ MTK_JPEG_FMT_TYPE_CAPTURE)) {
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev, "format change\n");
+ return true;
+ }
+ return false;
+}
+
+static void mtk_jpeg_set_queue_data(struct mtk_jpeg_ctx *ctx,
+ struct mtk_jpeg_dec_param *param)
+{
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ struct mtk_jpeg_q_data *q_data;
+ int i;
+
+ q_data = &ctx->out_q;
+ q_data->w = param->pic_w;
+ q_data->h = param->pic_h;
+
+ q_data = &ctx->cap_q;
+ q_data->w = param->dec_w;
+ q_data->h = param->dec_h;
+ q_data->fmt = mtk_jpeg_find_format(ctx,
+ param->dst_fourcc,
+ MTK_JPEG_FMT_TYPE_CAPTURE);
+
+ for (i = 0; i < q_data->fmt->colplanes; i++) {
+ q_data->bytesperline[i] = param->mem_stride[i];
+ q_data->sizeimage[i] = param->comp_size[i];
+ }
+
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev,
+ "set_parse cap:%c%c%c%c pic(%u, %u), buf(%u, %u)\n",
+ (param->dst_fourcc & 0xff),
+ (param->dst_fourcc >> 8 & 0xff),
+ (param->dst_fourcc >> 16 & 0xff),
+ (param->dst_fourcc >> 24 & 0xff),
+ param->pic_w, param->pic_h,
+ param->dec_w, param->dec_h);
+}
+
+static void mtk_jpeg_buf_queue(struct vb2_buffer *vb)
+{
+ struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(vb->vb2_queue);
+ struct mtk_jpeg_dec_param *param;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ struct mtk_jpeg_src_buf *jpeg_src_buf;
+ bool header_valid;
+
+ v4l2_dbg(2, debug, &jpeg->v4l2_dev, "(%d) buf_q id=%d, vb=%p\n",
+ vb->vb2_queue->type, vb->index, vb);
+
+ if (vb->vb2_queue->type != V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE)
+ goto end;
+
+ jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
+ param = &jpeg_src_buf->dec_param;
+ memset(param, 0, sizeof(*param));
+
+ if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) {
+ v4l2_dbg(1, debug, &jpeg->v4l2_dev, "Got eos\n");
+ goto end;
+ }
+ header_valid = mtk_jpeg_parse(param, (u8 *)vb2_plane_vaddr(vb, 0),
+ vb2_get_plane_payload(vb, 0));
+ if (!header_valid) {
+ v4l2_err(&jpeg->v4l2_dev, "Header invalid.\n");
+ vb2_buffer_done(vb, VB2_BUF_STATE_ERROR);
+ return;
+ }
+
+ if (ctx->state == MTK_JPEG_INIT) {
+ mtk_jpeg_queue_src_chg_event(ctx);
+ mtk_jpeg_set_queue_data(ctx, param);
+ ctx->state = MTK_JPEG_RUNNING;
+ }
+end:
+ v4l2_m2m_buf_queue(ctx->fh.m2m_ctx, to_vb2_v4l2_buffer(vb));
+}
+
+static void *mtk_jpeg_buf_remove(struct mtk_jpeg_ctx *ctx,
+ enum v4l2_buf_type type)
+{
+ if (V4L2_TYPE_IS_OUTPUT(type))
+ return v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ else
+ return v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+}
+
+static int mtk_jpeg_start_streaming(struct vb2_queue *q, unsigned int count)
+{
+ struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+ struct vb2_buffer *vb;
+ int ret = 0;
+
+ ret = pm_runtime_get_sync(ctx->jpeg->dev);
+ if (ret < 0)
+ goto err;
+
+ return 0;
+err:
+ while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_QUEUED);
+ return ret;
+}
+
+static void mtk_jpeg_stop_streaming(struct vb2_queue *q)
+{
+ struct mtk_jpeg_ctx *ctx = vb2_get_drv_priv(q);
+ struct vb2_buffer *vb;
+
+ /*
+ * STREAMOFF is an acknowledgment for source change event.
+ * Before STREAMOFF, we still have to return the old resolution and
+ * subsampling. Update capture queue when the stream is off.
+ */
+ if (ctx->state == MTK_JPEG_SOURCE_CHANGE &&
+ !V4L2_TYPE_IS_OUTPUT(q->type)) {
+ struct mtk_jpeg_src_buf *src_buf;
+
+ vb = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ src_buf = mtk_jpeg_vb2_to_srcbuf(vb);
+ mtk_jpeg_set_queue_data(ctx, &src_buf->dec_param);
+ ctx->state = MTK_JPEG_RUNNING;
+ } else if (V4L2_TYPE_IS_OUTPUT(q->type)) {
+ ctx->state = MTK_JPEG_INIT;
+ }
+
+ while ((vb = mtk_jpeg_buf_remove(ctx, q->type)))
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(vb), VB2_BUF_STATE_ERROR);
+
+ pm_runtime_put_sync(ctx->jpeg->dev);
+}
+
+static struct vb2_ops mtk_jpeg_qops = {
+ .queue_setup = mtk_jpeg_queue_setup,
+ .buf_prepare = mtk_jpeg_buf_prepare,
+ .buf_queue = mtk_jpeg_buf_queue,
+ .wait_prepare = vb2_ops_wait_prepare,
+ .wait_finish = vb2_ops_wait_finish,
+ .start_streaming = mtk_jpeg_start_streaming,
+ .stop_streaming = mtk_jpeg_stop_streaming,
+};
+
+static void mtk_jpeg_set_dec_src(struct mtk_jpeg_ctx *ctx,
+ struct vb2_buffer *src_buf,
+ struct mtk_jpeg_bs *bs)
+{
+ bs->str_addr = vb2_dma_contig_plane_dma_addr(src_buf, 0);
+ bs->end_addr = bs->str_addr +
+ mtk_jpeg_align(vb2_get_plane_payload(src_buf, 0), 16);
+ bs->size = mtk_jpeg_align(vb2_plane_size(src_buf, 0), 128);
+}
+
+static int mtk_jpeg_set_dec_dst(struct mtk_jpeg_ctx *ctx,
+ struct mtk_jpeg_dec_param *param,
+ struct vb2_buffer *dst_buf,
+ struct mtk_jpeg_fb *fb)
+{
+ int i;
+
+ if (param->comp_num != dst_buf->num_planes) {
+ dev_err(ctx->jpeg->dev, "plane number mismatch (%u != %u)\n",
+ param->comp_num, dst_buf->num_planes);
+ return -EINVAL;
+ }
+
+ for (i = 0; i < dst_buf->num_planes; i++) {
+ if (vb2_plane_size(dst_buf, i) < param->comp_size[i]) {
+ dev_err(ctx->jpeg->dev,
+ "buffer size is underflow (%lu < %u)\n",
+ vb2_plane_size(dst_buf, 0),
+ param->comp_size[i]);
+ return -EINVAL;
+ }
+ fb->plane_addr[i] = vb2_dma_contig_plane_dma_addr(dst_buf, i);
+ }
+
+ return 0;
+}
+
+static void mtk_jpeg_device_run(void *priv)
+{
+ struct mtk_jpeg_ctx *ctx = priv;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ struct vb2_buffer *src_buf, *dst_buf;
+ enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+ unsigned long flags;
+ struct mtk_jpeg_src_buf *jpeg_src_buf;
+ struct mtk_jpeg_bs bs;
+ struct mtk_jpeg_fb fb;
+ int i;
+
+ src_buf = v4l2_m2m_next_src_buf(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_next_dst_buf(ctx->fh.m2m_ctx);
+ jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf);
+
+ if (jpeg_src_buf->flags & MTK_JPEG_BUF_FLAGS_LAST_FRAME) {
+ for (i = 0; i < dst_buf->num_planes; i++)
+ vb2_set_plane_payload(dst_buf, i, 0);
+ buf_state = VB2_BUF_STATE_DONE;
+ goto dec_end;
+ }
+
+ if (mtk_jpeg_check_resolution_change(ctx, &jpeg_src_buf->dec_param)) {
+ mtk_jpeg_queue_src_chg_event(ctx);
+ ctx->state = MTK_JPEG_SOURCE_CHANGE;
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ return;
+ }
+
+ mtk_jpeg_set_dec_src(ctx, src_buf, &bs);
+ if (mtk_jpeg_set_dec_dst(ctx, &jpeg_src_buf->dec_param, dst_buf, &fb))
+ goto dec_end;
+
+ spin_lock_irqsave(&jpeg->hw_lock, flags);
+ mtk_jpeg_dec_reset(jpeg->dec_reg_base);
+ mtk_jpeg_dec_set_config(jpeg->dec_reg_base,
+ &jpeg_src_buf->dec_param, &bs, &fb);
+
+ mtk_jpeg_dec_start(jpeg->dec_reg_base);
+ spin_unlock_irqrestore(&jpeg->hw_lock, flags);
+ return;
+
+dec_end:
+ v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state);
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static int mtk_jpeg_job_ready(void *priv)
+{
+ struct mtk_jpeg_ctx *ctx = priv;
+
+ return (ctx->state == MTK_JPEG_RUNNING) ? 1 : 0;
+}
+
+static void mtk_jpeg_job_abort(void *priv)
+{
+ struct mtk_jpeg_ctx *ctx = priv;
+ struct mtk_jpeg_dev *jpeg = ctx->jpeg;
+ struct vb2_buffer *src_buf, *dst_buf;
+
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), VB2_BUF_STATE_ERROR);
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), VB2_BUF_STATE_ERROR);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+}
+
+static struct v4l2_m2m_ops mtk_jpeg_m2m_ops = {
+ .device_run = mtk_jpeg_device_run,
+ .job_ready = mtk_jpeg_job_ready,
+ .job_abort = mtk_jpeg_job_abort,
+};
+
+static int mtk_jpeg_queue_init(void *priv, struct vb2_queue *src_vq,
+ struct vb2_queue *dst_vq)
+{
+ struct mtk_jpeg_ctx *ctx = priv;
+ int ret;
+
+ src_vq->type = V4L2_BUF_TYPE_VIDEO_OUTPUT_MPLANE;
+ src_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+ src_vq->drv_priv = ctx;
+ src_vq->buf_struct_size = sizeof(struct mtk_jpeg_src_buf);
+ src_vq->ops = &mtk_jpeg_qops;
+ src_vq->mem_ops = &vb2_dma_contig_memops;
+ src_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ src_vq->lock = &ctx->jpeg->lock;
+ src_vq->dev = ctx->jpeg->dev;
+ ret = vb2_queue_init(src_vq);
+ if (ret)
+ return ret;
+
+ dst_vq->type = V4L2_BUF_TYPE_VIDEO_CAPTURE_MPLANE;
+ dst_vq->io_modes = VB2_DMABUF | VB2_MMAP;
+ dst_vq->drv_priv = ctx;
+ dst_vq->buf_struct_size = sizeof(struct v4l2_m2m_buffer);
+ dst_vq->ops = &mtk_jpeg_qops;
+ dst_vq->mem_ops = &vb2_dma_contig_memops;
+ dst_vq->timestamp_flags = V4L2_BUF_FLAG_TIMESTAMP_COPY;
+ dst_vq->lock = &ctx->jpeg->lock;
+ dst_vq->dev = ctx->jpeg->dev;
+ ret = vb2_queue_init(dst_vq);
+
+ return ret;
+}
+
+static void mtk_jpeg_clk_on(struct mtk_jpeg_dev *jpeg)
+{
+ int ret;
+
+ ret = mtk_smi_larb_get(jpeg->larb);
+ if (ret)
+ dev_err(jpeg->dev, "mtk_smi_larb_get larbvdec fail %d\n", ret);
+ clk_prepare_enable(jpeg->clk_jdec_smi);
+ clk_prepare_enable(jpeg->clk_jdec);
+}
+
+static void mtk_jpeg_clk_off(struct mtk_jpeg_dev *jpeg)
+{
+ clk_disable_unprepare(jpeg->clk_jdec);
+ clk_disable_unprepare(jpeg->clk_jdec_smi);
+ mtk_smi_larb_put(jpeg->larb);
+}
+
+static irqreturn_t mtk_jpeg_dec_irq(int irq, void *priv)
+{
+ struct mtk_jpeg_dev *jpeg = priv;
+ struct mtk_jpeg_ctx *ctx;
+ struct vb2_buffer *src_buf, *dst_buf;
+ struct mtk_jpeg_src_buf *jpeg_src_buf;
+ enum vb2_buffer_state buf_state = VB2_BUF_STATE_ERROR;
+ u32 dec_irq_ret;
+ u32 dec_ret;
+ int i;
+
+ ctx = v4l2_m2m_get_curr_priv(jpeg->m2m_dev);
+ if (!ctx) {
+ v4l2_err(&jpeg->v4l2_dev, "Context is NULL\n");
+ return IRQ_HANDLED;
+ }
+
+ src_buf = v4l2_m2m_src_buf_remove(ctx->fh.m2m_ctx);
+ dst_buf = v4l2_m2m_dst_buf_remove(ctx->fh.m2m_ctx);
+ jpeg_src_buf = mtk_jpeg_vb2_to_srcbuf(src_buf);
+
+ dec_ret = mtk_jpeg_dec_get_int_status(jpeg->dec_reg_base);
+ dec_irq_ret = mtk_jpeg_dec_enum_result(dec_ret);
+
+ if (dec_irq_ret >= MTK_JPEG_DEC_RESULT_UNDERFLOW)
+ mtk_jpeg_dec_reset(jpeg->dec_reg_base);
+
+ if (dec_irq_ret != MTK_JPEG_DEC_RESULT_EOF_DONE) {
+ dev_err(jpeg->dev, "decode failed\n");
+ goto dec_end;
+ }
+
+ for (i = 0; i < dst_buf->num_planes; i++)
+ vb2_set_plane_payload(dst_buf, i,
+ jpeg_src_buf->dec_param.comp_size[i]);
+
+ buf_state = VB2_BUF_STATE_DONE;
+
+dec_end:
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(src_buf), buf_state);
+ v4l2_m2m_buf_done(to_vb2_v4l2_buffer(dst_buf), buf_state);
+ v4l2_m2m_job_finish(jpeg->m2m_dev, ctx->fh.m2m_ctx);
+ return IRQ_HANDLED;
+}
+
+static void mtk_jpeg_set_default_params(struct mtk_jpeg_ctx *ctx)
+{
+ struct mtk_jpeg_q_data *q = &ctx->out_q;
+ int i;
+
+ ctx->colorspace = V4L2_COLORSPACE_JPEG,
+ ctx->ycbcr_enc = V4L2_YCBCR_ENC_DEFAULT;
+ ctx->quantization = V4L2_QUANTIZATION_DEFAULT;
+ ctx->xfer_func = V4L2_XFER_FUNC_DEFAULT;
+
+ q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_JPEG,
+ MTK_JPEG_FMT_TYPE_OUTPUT);
+ q->w = MTK_JPEG_MIN_WIDTH;
+ q->h = MTK_JPEG_MIN_HEIGHT;
+ q->bytesperline[0] = 0;
+ q->sizeimage[0] = MTK_JPEG_DEFAULT_SIZEIMAGE;
+
+ q = &ctx->cap_q;
+ q->fmt = mtk_jpeg_find_format(ctx, V4L2_PIX_FMT_YUV420M,
+ MTK_JPEG_FMT_TYPE_CAPTURE);
+ q->w = MTK_JPEG_MIN_WIDTH;
+ q->h = MTK_JPEG_MIN_HEIGHT;
+
+ for (i = 0; i < q->fmt->colplanes; i++) {
+ u32 stride = q->w * q->fmt->h_sample[i] / 4;
+ u32 h = q->h * q->fmt->v_sample[i] / 4;
+
+ q->bytesperline[i] = stride;
+ q->sizeimage[i] = stride * h;
+ }
+}
+
+static int mtk_jpeg_open(struct file *file)
+{
+ struct mtk_jpeg_dev *jpeg = video_drvdata(file);
+ struct video_device *vfd = video_devdata(file);
+ struct mtk_jpeg_ctx *ctx;
+ int ret = 0;
+
+ ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
+ if (!ctx)
+ return -ENOMEM;
+
+ if (mutex_lock_interruptible(&jpeg->lock)) {
+ ret = -ERESTARTSYS;
+ goto free;
+ }
+
+ v4l2_fh_init(&ctx->fh, vfd);
+ file->private_data = &ctx->fh;
+ v4l2_fh_add(&ctx->fh);
+
+ ctx->jpeg = jpeg;
+ ctx->fh.m2m_ctx = v4l2_m2m_ctx_init(jpeg->m2m_dev, ctx,
+ mtk_jpeg_queue_init);
+ if (IS_ERR(ctx->fh.m2m_ctx)) {
+ ret = PTR_ERR(ctx->fh.m2m_ctx);
+ goto error;
+ }
+
+ mtk_jpeg_set_default_params(ctx);
+ mutex_unlock(&jpeg->lock);
+ return 0;
+
+error:
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ mutex_unlock(&jpeg->lock);
+free:
+ kfree(ctx);
+ return ret;
+}
+
+static int mtk_jpeg_release(struct file *file)
+{
+ struct mtk_jpeg_dev *jpeg = video_drvdata(file);
+ struct mtk_jpeg_ctx *ctx = mtk_jpeg_fh_to_ctx(file->private_data);
+
+ mutex_lock(&jpeg->lock);
+ v4l2_m2m_ctx_release(ctx->fh.m2m_ctx);
+ v4l2_fh_del(&ctx->fh);
+ v4l2_fh_exit(&ctx->fh);
+ kfree(ctx);
+ mutex_unlock(&jpeg->lock);
+ return 0;
+}
+
+static const struct v4l2_file_operations mtk_jpeg_fops = {
+ .owner = THIS_MODULE,
+ .open = mtk_jpeg_open,
+ .release = mtk_jpeg_release,
+ .poll = v4l2_m2m_fop_poll,
+ .unlocked_ioctl = video_ioctl2,
+ .mmap = v4l2_m2m_fop_mmap,
+};
+
+static int mtk_jpeg_clk_init(struct mtk_jpeg_dev *jpeg)
+{
+ struct device_node *node;
+ struct platform_device *pdev;
+
+ node = of_parse_phandle(jpeg->dev->of_node, "mediatek,larb", 0);
+ if (!node)
+ return -EINVAL;
+ pdev = of_find_device_by_node(node);
+ if (WARN_ON(!pdev)) {
+ of_node_put(node);
+ return -EINVAL;
+ }
+ of_node_put(node);
+
+ jpeg->larb = &pdev->dev;
+
+ jpeg->clk_jdec = devm_clk_get(jpeg->dev, "jpgdec");
+ if (IS_ERR(jpeg->clk_jdec))
+ return -EINVAL;
+
+ jpeg->clk_jdec_smi = devm_clk_get(jpeg->dev, "jpgdec-smi");
+ if (IS_ERR(jpeg->clk_jdec_smi))
+ return -EINVAL;
+
+ return 0;
+}
+
+static int mtk_jpeg_probe(struct platform_device *pdev)
+{
+ struct mtk_jpeg_dev *jpeg;
+ struct resource *res;
+ int dec_irq;
+ int ret;
+
+ jpeg = devm_kzalloc(&pdev->dev, sizeof(*jpeg), GFP_KERNEL);
+ if (!jpeg)
+ return -ENOMEM;
+
+ mutex_init(&jpeg->lock);
+ spin_lock_init(&jpeg->hw_lock);
+ jpeg->dev = &pdev->dev;
+
+ res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+ jpeg->dec_reg_base = devm_ioremap_resource(&pdev->dev, res);
+ if (IS_ERR(jpeg->dec_reg_base)) {
+ ret = PTR_ERR(jpeg->dec_reg_base);
+ return ret;
+ }
+
+ res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+ dec_irq = platform_get_irq(pdev, 0);
+ if (!res || dec_irq < 0) {
+ dev_err(&pdev->dev, "Failed to get dec_irq %d.\n", dec_irq);
+ ret = -EINVAL;
+ return ret;
+ }
+
+ ret = devm_request_irq(&pdev->dev, dec_irq, mtk_jpeg_dec_irq, 0,
+ pdev->name, jpeg);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to request dec_irq %d (%d)\n",
+ dec_irq, ret);
+ ret = -EINVAL;
+ goto err_req_irq;
+ }
+
+ ret = mtk_jpeg_clk_init(jpeg);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to init clk, err %d\n", ret);
+ goto err_clk_init;
+ }
+
+ ret = v4l2_device_register(&pdev->dev, &jpeg->v4l2_dev);
+ if (ret) {
+ dev_err(&pdev->dev, "Failed to register v4l2 device\n");
+ ret = -EINVAL;
+ goto err_dev_register;
+ }
+
+ jpeg->m2m_dev = v4l2_m2m_init(&mtk_jpeg_m2m_ops);
+ if (IS_ERR(jpeg->m2m_dev)) {
+ v4l2_err(&jpeg->v4l2_dev, "Failed to init mem2mem device\n");
+ ret = PTR_ERR(jpeg->m2m_dev);
+ goto err_m2m_init;
+ }
+
+ jpeg->dec_vdev = video_device_alloc();
+ if (!jpeg->dec_vdev) {
+ ret = -ENOMEM;
+ goto err_dec_vdev_alloc;
+ }
+ snprintf(jpeg->dec_vdev->name, sizeof(jpeg->dec_vdev->name),
+ "%s-dec", MTK_JPEG_NAME);
+ jpeg->dec_vdev->fops = &mtk_jpeg_fops;
+ jpeg->dec_vdev->ioctl_ops = &mtk_jpeg_ioctl_ops;
+ jpeg->dec_vdev->minor = -1;
+ jpeg->dec_vdev->release = video_device_release;
+ jpeg->dec_vdev->lock = &jpeg->lock;
+ jpeg->dec_vdev->v4l2_dev = &jpeg->v4l2_dev;
+ jpeg->dec_vdev->vfl_dir = VFL_DIR_M2M;
+ jpeg->dec_vdev->device_caps = V4L2_CAP_STREAMING |
+ V4L2_CAP_VIDEO_M2M_MPLANE;
+
+ ret = video_register_device(jpeg->dec_vdev, VFL_TYPE_GRABBER, 3);
+ if (ret) {
+ v4l2_err(&jpeg->v4l2_dev, "Failed to register video device\n");
+ goto err_dec_vdev_register;
+ }
+
+ video_set_drvdata(jpeg->dec_vdev, jpeg);
+ v4l2_info(&jpeg->v4l2_dev,
+ "decoder device registered as /dev/video%d (%d,%d)\n",
+ jpeg->dec_vdev->num, VIDEO_MAJOR, jpeg->dec_vdev->minor);
+
+ platform_set_drvdata(pdev, jpeg);
+
+ pm_runtime_enable(&pdev->dev);
+
+ return 0;
+
+err_dec_vdev_register:
+ video_device_release(jpeg->dec_vdev);
+
+err_dec_vdev_alloc:
+ v4l2_m2m_release(jpeg->m2m_dev);
+
+err_m2m_init:
+ v4l2_device_unregister(&jpeg->v4l2_dev);
+
+err_dev_register:
+
+err_clk_init:
+
+err_req_irq:
+
+ return ret;
+}
+
+static int mtk_jpeg_remove(struct platform_device *pdev)
+{
+ struct mtk_jpeg_dev *jpeg = platform_get_drvdata(pdev);
+
+ pm_runtime_disable(&pdev->dev);
+ video_unregister_device(jpeg->dec_vdev);
+ video_device_release(jpeg->dec_vdev);
+ v4l2_m2m_release(jpeg->m2m_dev);
+ v4l2_device_unregister(&jpeg->v4l2_dev);
+
+ return 0;
+}
+
+#ifdef CONFIG_PM
+static int mtk_jpeg_pm_suspend(struct device *dev)
+{
+ struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
+
+ mtk_jpeg_dec_reset(jpeg->dec_reg_base);
+ mtk_jpeg_clk_off(jpeg);
+
+ return 0;
+}
+
+static int mtk_jpeg_pm_resume(struct device *dev)
+{
+ struct mtk_jpeg_dev *jpeg = dev_get_drvdata(dev);
+
+ mtk_jpeg_clk_on(jpeg);
+ mtk_jpeg_dec_reset(jpeg->dec_reg_base);
+
+ return 0;
+}
+#endif /* CONFIG_PM */
+
+#ifdef CONFIG_PM_SLEEP
+static int mtk_jpeg_suspend(struct device *dev)
+{
+ int ret;
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ ret = mtk_jpeg_pm_suspend(dev);
+ return ret;
+}
+
+static int mtk_jpeg_resume(struct device *dev)
+{
+ int ret;
+
+ if (pm_runtime_suspended(dev))
+ return 0;
+
+ ret = mtk_jpeg_pm_resume(dev);
+
+ return ret;
+}
+#endif /* CONFIG_PM_SLEEP */
+
+static const struct dev_pm_ops mtk_jpeg_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(mtk_jpeg_suspend, mtk_jpeg_resume)
+ SET_RUNTIME_PM_OPS(mtk_jpeg_pm_suspend, mtk_jpeg_pm_resume, NULL)
+};
+
+static const struct of_device_id mtk_jpeg_match[] = {
+ {
+ .compatible = "mediatek,mt8173-jpgdec",
+ .data = NULL,
+ },
+ {
+ .compatible = "mediatek,mt2701-jpgdec",
+ .data = NULL,
+ },
+ {},
+};
+
+MODULE_DEVICE_TABLE(of, mtk_jpeg_match);
+
+static struct platform_driver mtk_jpeg_driver = {
+ .probe = mtk_jpeg_probe,
+ .remove = mtk_jpeg_remove,
+ .driver = {
+ .owner = THIS_MODULE,
+ .name = MTK_JPEG_NAME,
+ .of_match_table = mtk_jpeg_match,
+ .pm = &mtk_jpeg_pm_ops,
+ },
+};
+
+module_platform_driver(mtk_jpeg_driver);
+
+MODULE_DESCRIPTION("MediaTek JPEG codec driver");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
new file mode 100644
index 0000000..1a6cdfd
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
@@ -0,0 +1,139 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ * Rick Chang <rick.chang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MTK_JPEG_CORE_H
+#define _MTK_JPEG_CORE_H
+
+#include <linux/interrupt.h>
+#include <media/v4l2-ctrls.h>
+#include <media/v4l2-device.h>
+#include <media/v4l2-fh.h>
+
+#define MTK_JPEG_NAME "mtk-jpeg"
+
+#define MTK_JPEG_FMT_FLAG_DEC_OUTPUT BIT(0)
+#define MTK_JPEG_FMT_FLAG_DEC_CAPTURE BIT(1)
+
+#define MTK_JPEG_FMT_TYPE_OUTPUT 1
+#define MTK_JPEG_FMT_TYPE_CAPTURE 2
+
+#define MTK_JPEG_MIN_WIDTH 32
+#define MTK_JPEG_MIN_HEIGHT 32
+#define MTK_JPEG_MAX_WIDTH 8192
+#define MTK_JPEG_MAX_HEIGHT 8192
+
+#define MTK_JPEG_DEFAULT_SIZEIMAGE (1 * 1024 * 1024)
+
+enum mtk_jpeg_ctx_state {
+ MTK_JPEG_INIT = 0,
+ MTK_JPEG_RUNNING,
+ MTK_JPEG_SOURCE_CHANGE,
+};
+
+/**
+ * struct mt_jpeg - JPEG IP abstraction
+ * @lock: the mutex protecting this structure
+ * @hw_lock: spinlock protecting the hw device resource
+ * @workqueue: decode work queue
+ * @dev: JPEG device
+ * @v4l2_dev: v4l2 device for mem2mem mode
+ * @m2m_dev: v4l2 mem2mem device data
+ * @alloc_ctx: videobuf2 memory allocator's context
+ * @dec_vdev: video device node for decoder mem2mem mode
+ * @dec_reg_base: JPEG registers mapping
+ * @clk_jdec: JPEG hw working clock
+ * @clk_jdec_smi: JPEG SMI bus clock
+ * @larb: SMI device
+ */
+struct mtk_jpeg_dev {
+ struct mutex lock;
+ spinlock_t hw_lock;
+ struct workqueue_struct *workqueue;
+ struct device *dev;
+ struct v4l2_device v4l2_dev;
+ struct v4l2_m2m_dev *m2m_dev;
+ void *alloc_ctx;
+ struct video_device *dec_vdev;
+ void __iomem *dec_reg_base;
+ struct clk *clk_jdec;
+ struct clk *clk_jdec_smi;
+ struct device *larb;
+};
+
+/**
+ * struct jpeg_fmt - driver's internal color format data
+ * @fourcc: the fourcc code, 0 if not applicable
+ * @h_sample: horizontal sample count of plane in 4 * 4 pixel image
+ * @v_sample: vertical sample count of plane in 4 * 4 pixel image
+ * @colplanes: number of color planes (1 for packed formats)
+ * @h_align: horizontal alignment order (align to 2^h_align)
+ * @v_align: vertical alignment order (align to 2^v_align)
+ * @flags: flags describing format applicability
+ */
+struct mtk_jpeg_fmt {
+ u32 fourcc;
+ int h_sample[VIDEO_MAX_PLANES];
+ int v_sample[VIDEO_MAX_PLANES];
+ int colplanes;
+ int h_align;
+ int v_align;
+ u32 flags;
+};
+
+/**
+ * mtk_jpeg_q_data - parameters of one queue
+ * @fmt: driver-specific format of this queue
+ * @w: image width
+ * @h: image height
+ * @bytesperline: distance in bytes between the leftmost pixels in two adjacent
+ * lines
+ * @sizeimage: image buffer size in bytes
+ */
+struct mtk_jpeg_q_data {
+ struct mtk_jpeg_fmt *fmt;
+ u32 w;
+ u32 h;
+ u32 bytesperline[VIDEO_MAX_PLANES];
+ u32 sizeimage[VIDEO_MAX_PLANES];
+};
+
+/**
+ * mtk_jpeg_ctx - the device context data
+ * @jpeg: JPEG IP device for this context
+ * @out_q: source (output) queue information
+ * @cap_q: destination (capture) queue queue information
+ * @fh: V4L2 file handle
+ * @dec_param parameters for HW decoding
+ * @state: state of the context
+ * @header_valid: set if header has been parsed and valid
+ * @colorspace: enum v4l2_colorspace; supplemental to pixelformat
+ * @ycbcr_enc: enum v4l2_ycbcr_encoding, Y'CbCr encoding
+ * @quantization: enum v4l2_quantization, colorspace quantization
+ * @xfer_func: enum v4l2_xfer_func, colorspace transfer function
+ */
+struct mtk_jpeg_ctx {
+ struct mtk_jpeg_dev *jpeg;
+ struct mtk_jpeg_q_data out_q;
+ struct mtk_jpeg_q_data cap_q;
+ struct v4l2_fh fh;
+ enum mtk_jpeg_ctx_state state;
+
+ enum v4l2_colorspace colorspace;
+ enum v4l2_ycbcr_encoding ycbcr_enc;
+ enum v4l2_quantization quantization;
+ enum v4l2_xfer_func xfer_func;
+};
+
+#endif /* _MTK_JPEG_CORE_H */
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c
new file mode 100644
index 0000000..77b4cc6
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ * Rick Chang <rick.chang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/io.h>
+#include <linux/kernel.h>
+#include <media/videobuf2-core.h>
+
+#include "mtk_jpeg_hw.h"
+
+#define MTK_JPEG_DUNUM_MASK(val) (((val) - 1) & 0x3)
+
+enum mtk_jpeg_color {
+ MTK_JPEG_COLOR_420 = 0x00221111,
+ MTK_JPEG_COLOR_422 = 0x00211111,
+ MTK_JPEG_COLOR_444 = 0x00111111,
+ MTK_JPEG_COLOR_422V = 0x00121111,
+ MTK_JPEG_COLOR_422X2 = 0x00412121,
+ MTK_JPEG_COLOR_422VX2 = 0x00222121,
+ MTK_JPEG_COLOR_400 = 0x00110000
+};
+
+static inline int mtk_jpeg_verify_align(u32 val, int align, u32 reg)
+{
+ if (val & (align - 1)) {
+ pr_err("mtk-jpeg: write reg %x without %d align\n", reg, align);
+ return -1;
+ }
+
+ return 0;
+}
+
+static int mtk_jpeg_decide_format(struct mtk_jpeg_dec_param *param)
+{
+ param->src_color = (param->sampling_w[0] << 20) |
+ (param->sampling_h[0] << 16) |
+ (param->sampling_w[1] << 12) |
+ (param->sampling_h[1] << 8) |
+ (param->sampling_w[2] << 4) |
+ (param->sampling_h[2]);
+
+ param->uv_brz_w = 0;
+ switch (param->src_color) {
+ case MTK_JPEG_COLOR_444:
+ param->uv_brz_w = 1;
+ param->dst_fourcc = V4L2_PIX_FMT_YUV422M;
+ break;
+ case MTK_JPEG_COLOR_422X2:
+ case MTK_JPEG_COLOR_422:
+ param->dst_fourcc = V4L2_PIX_FMT_YUV422M;
+ break;
+ case MTK_JPEG_COLOR_422V:
+ case MTK_JPEG_COLOR_422VX2:
+ param->uv_brz_w = 1;
+ param->dst_fourcc = V4L2_PIX_FMT_YUV420M;
+ break;
+ case MTK_JPEG_COLOR_420:
+ param->dst_fourcc = V4L2_PIX_FMT_YUV420M;
+ break;
+ case MTK_JPEG_COLOR_400:
+ param->dst_fourcc = V4L2_PIX_FMT_GREY;
+ break;
+ default:
+ param->dst_fourcc = 0;
+ return -1;
+ }
+
+ return 0;
+}
+
+static void mtk_jpeg_calc_mcu(struct mtk_jpeg_dec_param *param)
+{
+ u32 factor_w, factor_h;
+ u32 i, comp, blk;
+
+ factor_w = 2 + param->sampling_w[0];
+ factor_h = 2 + param->sampling_h[0];
+ param->mcu_w = (param->pic_w + (1 << factor_w) - 1) >> factor_w;
+ param->mcu_h = (param->pic_h + (1 << factor_h) - 1) >> factor_h;
+ param->total_mcu = param->mcu_w * param->mcu_h;
+ param->unit_num = ((param->pic_w + 7) >> 3) * ((param->pic_h + 7) >> 3);
+ param->blk_num = 0;
+ for (i = 0; i < MTK_JPEG_COMP_MAX; i++) {
+ param->blk_comp[i] = 0;
+ if (i >= param->comp_num)
+ continue;
+ param->blk_comp[i] = param->sampling_w[i] *
+ param->sampling_h[i];
+ param->blk_num += param->blk_comp[i];
+ }
+
+ param->membership = 0;
+ for (i = 0, blk = 0, comp = 0; i < MTK_JPEG_BLOCK_MAX; i++) {
+ if (i < param->blk_num && comp < param->comp_num) {
+ u32 tmp;
+
+ tmp = (0x04 + (comp & 0x3));
+ param->membership |= tmp << (i * 3);
+ if (++blk == param->blk_comp[comp]) {
+ comp++;
+ blk = 0;
+ }
+ } else {
+ param->membership |= 7 << (i * 3);
+ }
+ }
+}
+
+static void mtk_jpeg_calc_dma_group(struct mtk_jpeg_dec_param *param)
+{
+ u32 factor_mcu = 3;
+
+ if (param->src_color == MTK_JPEG_COLOR_444 &&
+ param->dst_fourcc == V4L2_PIX_FMT_YUV422M)
+ factor_mcu = 4;
+ else if (param->src_color == MTK_JPEG_COLOR_422V &&
+ param->dst_fourcc == V4L2_PIX_FMT_YUV420M)
+ factor_mcu = 4;
+ else if (param->src_color == MTK_JPEG_COLOR_422X2 &&
+ param->dst_fourcc == V4L2_PIX_FMT_YUV422M)
+ factor_mcu = 2;
+ else if (param->src_color == MTK_JPEG_COLOR_400 ||
+ (param->src_color & 0x0FFFF) == 0)
+ factor_mcu = 4;
+
+ param->dma_mcu = 1 << factor_mcu;
+ param->dma_group = param->mcu_w / param->dma_mcu;
+ param->dma_last_mcu = param->mcu_w % param->dma_mcu;
+ if (param->dma_last_mcu)
+ param->dma_group++;
+ else
+ param->dma_last_mcu = param->dma_mcu;
+}
+
+static int mtk_jpeg_calc_dst_size(struct mtk_jpeg_dec_param *param)
+{
+ u32 i, padding_w;
+ u32 ds_row_h[3];
+ u32 brz_w[3];
+
+ brz_w[0] = 0;
+ brz_w[1] = param->uv_brz_w;
+ brz_w[2] = brz_w[1];
+
+ for (i = 0; i < param->comp_num; i++) {
+ if (brz_w[i] > 3)
+ return -1;
+
+ padding_w = param->mcu_w * MTK_JPEG_DCTSIZE *
+ param->sampling_w[i];
+ /* output format is 420/422 */
+ param->comp_w[i] = padding_w >> brz_w[i];
+ param->comp_w[i] = mtk_jpeg_align(param->comp_w[i],
+ MTK_JPEG_DCTSIZE);
+ param->img_stride[i] = i ? mtk_jpeg_align(param->comp_w[i], 16)
+ : mtk_jpeg_align(param->comp_w[i], 32);
+ ds_row_h[i] = (MTK_JPEG_DCTSIZE * param->sampling_h[i]);
+ }
+ param->dec_w = param->img_stride[0];
+ param->dec_h = ds_row_h[0] * param->mcu_h;
+
+ for (i = 0; i < MTK_JPEG_COMP_MAX; i++) {
+ /* They must be equal in frame mode. */
+ param->mem_stride[i] = param->img_stride[i];
+ param->comp_size[i] = param->mem_stride[i] * ds_row_h[i] *
+ param->mcu_h;
+ }
+
+ param->y_size = param->comp_size[0];
+ param->uv_size = param->comp_size[1];
+ param->dec_size = param->y_size + (param->uv_size << 1);
+
+ return 0;
+}
+
+int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param)
+{
+ if (mtk_jpeg_decide_format(param))
+ return -1;
+
+ mtk_jpeg_calc_mcu(param);
+ mtk_jpeg_calc_dma_group(param);
+ if (mtk_jpeg_calc_dst_size(param))
+ return -2;
+
+ return 0;
+}
+
+u32 mtk_jpeg_dec_get_int_status(void __iomem *base)
+{
+ u32 ret;
+
+ ret = readl(base + JPGDEC_REG_INTERRUPT_STATUS) & BIT_INQST_MASK_ALLIRQ;
+ if (ret)
+ writel(ret, base + JPGDEC_REG_INTERRUPT_STATUS);
+
+ return ret;
+}
+
+u32 mtk_jpeg_dec_enum_result(u32 irq_result)
+{
+ if (irq_result & BIT_INQST_MASK_EOF)
+ return MTK_JPEG_DEC_RESULT_EOF_DONE;
+ if (irq_result & BIT_INQST_MASK_PAUSE)
+ return MTK_JPEG_DEC_RESULT_PAUSE;
+ if (irq_result & BIT_INQST_MASK_UNDERFLOW)
+ return MTK_JPEG_DEC_RESULT_UNDERFLOW;
+ if (irq_result & BIT_INQST_MASK_OVERFLOW)
+ return MTK_JPEG_DEC_RESULT_OVERFLOW;
+ if (irq_result & BIT_INQST_MASK_ERROR_BS)
+ return MTK_JPEG_DEC_RESULT_ERROR_BS;
+
+ return MTK_JPEG_DEC_RESULT_ERROR_UNKNOWN;
+}
+
+void mtk_jpeg_dec_start(void __iomem *base)
+{
+ writel(0, base + JPGDEC_REG_TRIG);
+}
+
+static void mtk_jpeg_dec_soft_reset(void __iomem *base)
+{
+ writel(0x0000FFFF, base + JPGDEC_REG_INTERRUPT_STATUS);
+ writel(0x00, base + JPGDEC_REG_RESET);
+ writel(0x01, base + JPGDEC_REG_RESET);
+}
+
+static void mtk_jpeg_dec_hard_reset(void __iomem *base)
+{
+ writel(0x00, base + JPGDEC_REG_RESET);
+ writel(0x10, base + JPGDEC_REG_RESET);
+}
+
+void mtk_jpeg_dec_reset(void __iomem *base)
+{
+ mtk_jpeg_dec_soft_reset(base);
+ mtk_jpeg_dec_hard_reset(base);
+}
+
+static void mtk_jpeg_dec_set_brz_factor(void __iomem *base, u8 yscale_w,
+ u8 yscale_h, u8 uvscale_w, u8 uvscale_h)
+{
+ u32 val;
+
+ val = (uvscale_h << 12) | (uvscale_w << 8) |
+ (yscale_h << 4) | yscale_w;
+ writel(val, base + JPGDEC_REG_BRZ_FACTOR);
+}
+
+static void mtk_jpeg_dec_set_dst_bank0(void __iomem *base, u32 addr_y,
+ u32 addr_u, u32 addr_v)
+{
+ mtk_jpeg_verify_align(addr_y, 16, JPGDEC_REG_DEST_ADDR0_Y);
+ writel(addr_y, base + JPGDEC_REG_DEST_ADDR0_Y);
+ mtk_jpeg_verify_align(addr_u, 16, JPGDEC_REG_DEST_ADDR0_U);
+ writel(addr_u, base + JPGDEC_REG_DEST_ADDR0_U);
+ mtk_jpeg_verify_align(addr_v, 16, JPGDEC_REG_DEST_ADDR0_V);
+ writel(addr_v, base + JPGDEC_REG_DEST_ADDR0_V);
+}
+
+static void mtk_jpeg_dec_set_dst_bank1(void __iomem *base, u32 addr_y,
+ u32 addr_u, u32 addr_v)
+{
+ writel(addr_y, base + JPGDEC_REG_DEST_ADDR1_Y);
+ writel(addr_u, base + JPGDEC_REG_DEST_ADDR1_U);
+ writel(addr_v, base + JPGDEC_REG_DEST_ADDR1_V);
+}
+
+static void mtk_jpeg_dec_set_mem_stride(void __iomem *base, u32 stride_y,
+ u32 stride_uv)
+{
+ writel((stride_y & 0xFFFF), base + JPGDEC_REG_STRIDE_Y);
+ writel((stride_uv & 0xFFFF), base + JPGDEC_REG_STRIDE_UV);
+}
+
+static void mtk_jpeg_dec_set_img_stride(void __iomem *base, u32 stride_y,
+ u32 stride_uv)
+{
+ writel((stride_y & 0xFFFF), base + JPGDEC_REG_IMG_STRIDE_Y);
+ writel((stride_uv & 0xFFFF), base + JPGDEC_REG_IMG_STRIDE_UV);
+}
+
+static void mtk_jpeg_dec_set_pause_mcu_idx(void __iomem *base, u32 idx)
+{
+ writel(idx & 0x0003FFFFFF, base + JPGDEC_REG_PAUSE_MCU_NUM);
+}
+
+static void mtk_jpeg_dec_set_dec_mode(void __iomem *base, u32 mode)
+{
+ writel(mode & 0x03, base + JPGDEC_REG_OPERATION_MODE);
+}
+
+static void mtk_jpeg_dec_set_bs_write_ptr(void __iomem *base, u32 ptr)
+{
+ mtk_jpeg_verify_align(ptr, 16, JPGDEC_REG_FILE_BRP);
+ writel(ptr, base + JPGDEC_REG_FILE_BRP);
+}
+
+static void mtk_jpeg_dec_set_bs_info(void __iomem *base, u32 addr, u32 size)
+{
+ mtk_jpeg_verify_align(addr, 16, JPGDEC_REG_FILE_ADDR);
+ mtk_jpeg_verify_align(size, 128, JPGDEC_REG_FILE_TOTAL_SIZE);
+ writel(addr, base + JPGDEC_REG_FILE_ADDR);
+ writel(size, base + JPGDEC_REG_FILE_TOTAL_SIZE);
+}
+
+static void mtk_jpeg_dec_set_comp_id(void __iomem *base, u32 id_y, u32 id_u,
+ u32 id_v)
+{
+ u32 val;
+
+ val = ((id_y & 0x00FF) << 24) | ((id_u & 0x00FF) << 16) |
+ ((id_v & 0x00FF) << 8);
+ writel(val, base + JPGDEC_REG_COMP_ID);
+}
+
+static void mtk_jpeg_dec_set_total_mcu(void __iomem *base, u32 num)
+{
+ writel(num - 1, base + JPGDEC_REG_TOTAL_MCU_NUM);
+}
+
+static void mtk_jpeg_dec_set_comp0_du(void __iomem *base, u32 num)
+{
+ writel(num - 1, base + JPGDEC_REG_COMP0_DATA_UNIT_NUM);
+}
+
+static void mtk_jpeg_dec_set_du_membership(void __iomem *base, u32 member,
+ u32 gmc, u32 isgray)
+{
+ if (isgray)
+ member = 0x3FFFFFFC;
+ member |= (isgray << 31) | (gmc << 30);
+ writel(member, base + JPGDEC_REG_DU_CTRL);
+}
+
+static void mtk_jpeg_dec_set_q_table(void __iomem *base, u32 id0, u32 id1,
+ u32 id2)
+{
+ u32 val;
+
+ val = ((id0 & 0x0f) << 8) | ((id1 & 0x0f) << 4) | ((id2 & 0x0f) << 0);
+ writel(val, base + JPGDEC_REG_QT_ID);
+}
+
+static void mtk_jpeg_dec_set_dma_group(void __iomem *base, u32 mcu_group,
+ u32 group_num, u32 last_mcu)
+{
+ u32 val;
+
+ val = (((mcu_group - 1) & 0x00FF) << 16) |
+ (((group_num - 1) & 0x007F) << 8) |
+ ((last_mcu - 1) & 0x00FF);
+ writel(val, base + JPGDEC_REG_WDMA_CTRL);
+}
+
+static void mtk_jpeg_dec_set_sampling_factor(void __iomem *base, u32 comp_num,
+ u32 y_w, u32 y_h, u32 u_w,
+ u32 u_h, u32 v_w, u32 v_h)
+{
+ u32 val;
+ u32 y_wh = (MTK_JPEG_DUNUM_MASK(y_w) << 2) | MTK_JPEG_DUNUM_MASK(y_h);
+ u32 u_wh = (MTK_JPEG_DUNUM_MASK(u_w) << 2) | MTK_JPEG_DUNUM_MASK(u_h);
+ u32 v_wh = (MTK_JPEG_DUNUM_MASK(v_w) << 2) | MTK_JPEG_DUNUM_MASK(v_h);
+
+ if (comp_num == 1)
+ val = 0;
+ else
+ val = (y_wh << 8) | (u_wh << 4) | v_wh;
+ writel(val, base + JPGDEC_REG_DU_NUM);
+}
+
+void mtk_jpeg_dec_set_config(void __iomem *base,
+ struct mtk_jpeg_dec_param *config,
+ struct mtk_jpeg_bs *bs,
+ struct mtk_jpeg_fb *fb)
+{
+ mtk_jpeg_dec_set_brz_factor(base, 0, 0, config->uv_brz_w, 0);
+ mtk_jpeg_dec_set_dec_mode(base, 0);
+ mtk_jpeg_dec_set_comp0_du(base, config->unit_num);
+ mtk_jpeg_dec_set_total_mcu(base, config->total_mcu);
+ mtk_jpeg_dec_set_bs_info(base, bs->str_addr, bs->size);
+ mtk_jpeg_dec_set_bs_write_ptr(base, bs->end_addr);
+ mtk_jpeg_dec_set_du_membership(base, config->membership, 1,
+ (config->comp_num == 1) ? 1 : 0);
+ mtk_jpeg_dec_set_comp_id(base, config->comp_id[0], config->comp_id[1],
+ config->comp_id[2]);
+ mtk_jpeg_dec_set_q_table(base, config->qtbl_num[0],
+ config->qtbl_num[1], config->qtbl_num[2]);
+ mtk_jpeg_dec_set_sampling_factor(base, config->comp_num,
+ config->sampling_w[0],
+ config->sampling_h[0],
+ config->sampling_w[1],
+ config->sampling_h[1],
+ config->sampling_w[2],
+ config->sampling_h[2]);
+ mtk_jpeg_dec_set_mem_stride(base, config->mem_stride[0],
+ config->mem_stride[1]);
+ mtk_jpeg_dec_set_img_stride(base, config->img_stride[0],
+ config->img_stride[1]);
+ mtk_jpeg_dec_set_dst_bank0(base, fb->plane_addr[0],
+ fb->plane_addr[1], fb->plane_addr[2]);
+ mtk_jpeg_dec_set_dst_bank1(base, 0, 0, 0);
+ mtk_jpeg_dec_set_dma_group(base, config->dma_mcu, config->dma_group,
+ config->dma_last_mcu);
+ mtk_jpeg_dec_set_pause_mcu_idx(base, config->total_mcu);
+}
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h
new file mode 100644
index 0000000..37152a6
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ * Rick Chang <rick.chang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MTK_JPEG_HW_H
+#define _MTK_JPEG_HW_H
+
+#include <media/videobuf2-core.h>
+
+#include "mtk_jpeg_core.h"
+#include "mtk_jpeg_reg.h"
+
+enum {
+ MTK_JPEG_DEC_RESULT_EOF_DONE = 0,
+ MTK_JPEG_DEC_RESULT_PAUSE = 1,
+ MTK_JPEG_DEC_RESULT_UNDERFLOW = 2,
+ MTK_JPEG_DEC_RESULT_OVERFLOW = 3,
+ MTK_JPEG_DEC_RESULT_ERROR_BS = 4,
+ MTK_JPEG_DEC_RESULT_ERROR_UNKNOWN = 6
+};
+
+struct mtk_jpeg_dec_param {
+ u32 pic_w;
+ u32 pic_h;
+ u32 dec_w;
+ u32 dec_h;
+ u32 src_color;
+ u32 dst_fourcc;
+ u32 mcu_w;
+ u32 mcu_h;
+ u32 total_mcu;
+ u32 unit_num;
+ u32 comp_num;
+ u32 comp_id[MTK_JPEG_COMP_MAX];
+ u32 sampling_w[MTK_JPEG_COMP_MAX];
+ u32 sampling_h[MTK_JPEG_COMP_MAX];
+ u32 qtbl_num[MTK_JPEG_COMP_MAX];
+ u32 blk_num;
+ u32 blk_comp[MTK_JPEG_COMP_MAX];
+ u32 membership;
+ u32 dma_mcu;
+ u32 dma_group;
+ u32 dma_last_mcu;
+ u32 img_stride[MTK_JPEG_COMP_MAX];
+ u32 mem_stride[MTK_JPEG_COMP_MAX];
+ u32 comp_w[MTK_JPEG_COMP_MAX];
+ u32 comp_size[MTK_JPEG_COMP_MAX];
+ u32 y_size;
+ u32 uv_size;
+ u32 dec_size;
+ u8 uv_brz_w;
+};
+
+static inline u32 mtk_jpeg_align(u32 val, u32 align)
+{
+ return (val + align - 1) & ~(align - 1);
+}
+
+struct mtk_jpeg_bs {
+ dma_addr_t str_addr;
+ dma_addr_t end_addr;
+ size_t size;
+};
+
+struct mtk_jpeg_fb {
+ dma_addr_t plane_addr[MTK_JPEG_COMP_MAX];
+ size_t size;
+};
+
+int mtk_jpeg_dec_fill_param(struct mtk_jpeg_dec_param *param);
+u32 mtk_jpeg_dec_get_int_status(void __iomem *dec_reg_base);
+u32 mtk_jpeg_dec_enum_result(u32 irq_result);
+void mtk_jpeg_dec_set_config(void __iomem *base,
+ struct mtk_jpeg_dec_param *config,
+ struct mtk_jpeg_bs *bs,
+ struct mtk_jpeg_fb *fb);
+void mtk_jpeg_dec_reset(void __iomem *dec_reg_base);
+void mtk_jpeg_dec_start(void __iomem *dec_reg_base);
+
+#endif /* _MTK_JPEG_HW_H */
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c
new file mode 100644
index 0000000..3886854
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ * Rick Chang <rick.chang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/videodev2.h>
+
+#include "mtk_jpeg_parse.h"
+
+#define TEM 0x01
+#define SOF0 0xc0
+#define RST 0xd0
+#define SOI 0xd8
+#define EOI 0xd9
+
+struct mtk_jpeg_stream {
+ u8 *addr;
+ u32 size;
+ u32 curr;
+};
+
+static int read_byte(struct mtk_jpeg_stream *stream)
+{
+ if (stream->curr >= stream->size)
+ return -1;
+ return stream->addr[stream->curr++];
+}
+
+static int read_word_be(struct mtk_jpeg_stream *stream, u32 *word)
+{
+ u32 temp;
+ int byte;
+
+ byte = read_byte(stream);
+ if (byte == -1)
+ return -1;
+ temp = byte << 8;
+ byte = read_byte(stream);
+ if (byte == -1)
+ return -1;
+ *word = (u32)byte | temp;
+
+ return 0;
+}
+
+static void read_skip(struct mtk_jpeg_stream *stream, long len)
+{
+ if (len <= 0)
+ return;
+ while (len--)
+ read_byte(stream);
+}
+
+static bool mtk_jpeg_do_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
+ u32 src_size)
+{
+ bool notfound = true;
+ struct mtk_jpeg_stream stream;
+
+ stream.addr = src_addr_va;
+ stream.size = src_size;
+ stream.curr = 0;
+
+ while (notfound) {
+ int i, length, byte;
+ u32 word;
+
+ byte = read_byte(&stream);
+ if (byte == -1)
+ return false;
+ if (byte != 0xff)
+ continue;
+ do
+ byte = read_byte(&stream);
+ while (byte == 0xff);
+ if (byte == -1)
+ return false;
+ if (byte == 0)
+ continue;
+
+ length = 0;
+ switch (byte) {
+ case SOF0:
+ /* length */
+ if (read_word_be(&stream, &word))
+ break;
+
+ /* precision */
+ if (read_byte(&stream) == -1)
+ break;
+
+ if (read_word_be(&stream, &word))
+ break;
+ param->pic_h = word;
+
+ if (read_word_be(&stream, &word))
+ break;
+ param->pic_w = word;
+
+ param->comp_num = read_byte(&stream);
+ if (param->comp_num != 1 && param->comp_num != 3)
+ break;
+
+ for (i = 0; i < param->comp_num; i++) {
+ param->comp_id[i] = read_byte(&stream);
+ if (param->comp_id[i] == -1)
+ break;
+
+ /* sampling */
+ byte = read_byte(&stream);
+ if (byte == -1)
+ break;
+ param->sampling_w[i] = (byte >> 4) & 0x0F;
+ param->sampling_h[i] = byte & 0x0F;
+
+ param->qtbl_num[i] = read_byte(&stream);
+ if (param->qtbl_num[i] == -1)
+ break;
+ }
+
+ notfound = !(i == param->comp_num);
+ break;
+ case RST ... RST + 7:
+ case SOI:
+ case EOI:
+ case TEM:
+ break;
+ default:
+ if (read_word_be(&stream, &word))
+ break;
+ length = (long)word - 2;
+ read_skip(&stream, length);
+ break;
+ }
+ }
+
+ return !notfound;
+}
+
+bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
+ u32 src_size)
+{
+ if (!mtk_jpeg_do_parse(param, src_addr_va, src_size))
+ return false;
+ if (mtk_jpeg_dec_fill_param(param))
+ return false;
+
+ return true;
+}
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h
new file mode 100644
index 0000000..5d92340
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h
@@ -0,0 +1,25 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ * Rick Chang <rick.chang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MTK_JPEG_PARSE_H
+#define _MTK_JPEG_PARSE_H
+
+#include "mtk_jpeg_hw.h"
+
+bool mtk_jpeg_parse(struct mtk_jpeg_dec_param *param, u8 *src_addr_va,
+ u32 src_size);
+
+#endif /* _MTK_JPEG_PARSE_H */
+
diff --git a/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h b/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h
new file mode 100644
index 0000000..fc490d6
--- /dev/null
+++ b/drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h
@@ -0,0 +1,58 @@
+/*
+ * Copyright (c) 2016 MediaTek Inc.
+ * Author: Ming Hsiu Tsai <minghsiu.tsai@mediatek.com>
+ * Rick Chang <rick.chang@mediatek.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef _MTK_JPEG_REG_H
+#define _MTK_JPEG_REG_H
+
+#define MTK_JPEG_COMP_MAX 3
+#define MTK_JPEG_BLOCK_MAX 10
+#define MTK_JPEG_DCTSIZE 8
+
+#define BIT_INQST_MASK_ERROR_BS 0x20
+#define BIT_INQST_MASK_PAUSE 0x10
+#define BIT_INQST_MASK_OVERFLOW 0x04
+#define BIT_INQST_MASK_UNDERFLOW 0x02
+#define BIT_INQST_MASK_EOF 0x01
+#define BIT_INQST_MASK_ALLIRQ 0x37
+
+#define JPGDEC_REG_RESET 0x0090
+#define JPGDEC_REG_BRZ_FACTOR 0x00F8
+#define JPGDEC_REG_DU_NUM 0x00FC
+#define JPGDEC_REG_DEST_ADDR0_Y 0x0140
+#define JPGDEC_REG_DEST_ADDR0_U 0x0144
+#define JPGDEC_REG_DEST_ADDR0_V 0x0148
+#define JPGDEC_REG_DEST_ADDR1_Y 0x014C
+#define JPGDEC_REG_DEST_ADDR1_U 0x0150
+#define JPGDEC_REG_DEST_ADDR1_V 0x0154
+#define JPGDEC_REG_STRIDE_Y 0x0158
+#define JPGDEC_REG_STRIDE_UV 0x015C
+#define JPGDEC_REG_IMG_STRIDE_Y 0x0160
+#define JPGDEC_REG_IMG_STRIDE_UV 0x0164
+#define JPGDEC_REG_WDMA_CTRL 0x016C
+#define JPGDEC_REG_PAUSE_MCU_NUM 0x0170
+#define JPGDEC_REG_OPERATION_MODE 0x017C
+#define JPGDEC_REG_FILE_ADDR 0x0200
+#define JPGDEC_REG_COMP_ID 0x020C
+#define JPGDEC_REG_TOTAL_MCU_NUM 0x0210
+#define JPGDEC_REG_COMP0_DATA_UNIT_NUM 0x0224
+#define JPGDEC_REG_DU_CTRL 0x023C
+#define JPGDEC_REG_TRIG 0x0240
+#define JPGDEC_REG_FILE_BRP 0x0248
+#define JPGDEC_REG_FILE_TOTAL_SIZE 0x024C
+#define JPGDEC_REG_QT_ID 0x0270
+#define JPGDEC_REG_INTERRUPT_STATUS 0x0274
+#define JPGDEC_REG_STATUS 0x0278
+
+#endif /* _MTK_JPEG_REG_H */
--
1.9.1
^ permalink raw reply related
* [PATCH v6 1/3] dt-bindings: mediatek: Add a binding for Mediatek JPEG Decoder
From: Rick Chang @ 2016-11-17 3:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479353915-5043-1-git-send-email-rick.chang@mediatek.com>
Add a DT binding documentation for Mediatek JPEG Decoder of
MT2701 SoC.
Signed-off-by: Rick Chang <rick.chang@mediatek.com>
Signed-off-by: Minghsiu Tsai <minghsiu.tsai@mediatek.com>
Acked-by: Rob Herring <robh@kernel.org>
---
.../bindings/media/mediatek-jpeg-decoder.txt | 37 ++++++++++++++++++++++
1 file changed, 37 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
diff --git a/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
new file mode 100644
index 0000000..3813947
--- /dev/null
+++ b/Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
@@ -0,0 +1,37 @@
+* Mediatek JPEG Decoder
+
+Mediatek JPEG Decoder is the JPEG decode hardware present in Mediatek SoCs
+
+Required properties:
+- compatible : must be one of the following string:
+ "mediatek,mt8173-jpgdec"
+ "mediatek,mt2701-jpgdec"
+- reg : physical base address of the jpeg decoder registers and length of
+ memory mapped region.
+- interrupts : interrupt number to the interrupt controller.
+- clocks: device clocks, see
+ Documentation/devicetree/bindings/clock/clock-bindings.txt for details.
+- clock-names: must contain "jpgdec-smi" and "jpgdec".
+- power-domains: a phandle to the power domain, see
+ Documentation/devicetree/bindings/power/power_domain.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.
+- iommus: should point to the respective IOMMU block with master port as
+ argument, see Documentation/devicetree/bindings/iommu/mediatek,iommu.txt
+ for details.
+
+Example:
+ jpegdec: jpegdec at 15004000 {
+ compatible = "mediatek,mt2701-jpgdec";
+ reg = <0 0x15004000 0 0x1000>;
+ interrupts = <GIC_SPI 143 IRQ_TYPE_LEVEL_LOW>;
+ clocks = <&imgsys CLK_IMG_JPGDEC_SMI>,
+ <&imgsys CLK_IMG_JPGDEC>;
+ clock-names = "jpgdec-smi",
+ "jpgdec";
+ power-domains = <&scpsys MT2701_POWER_DOMAIN_ISP>;
+ mediatek,larb = <&larb2>;
+ iommus = <&iommu MT2701_M4U_PORT_JPGDEC_WDMA>,
+ <&iommu MT2701_M4U_PORT_JPGDEC_BSDMA>;
+ };
--
1.9.1
^ permalink raw reply related
* [PATCH v6 0/3] Add Mediatek JPEG Decoder
From: Rick Chang @ 2016-11-17 3:38 UTC (permalink / raw)
To: linux-arm-kernel
This series of patches provide a v4l2 driver to control Mediatek JPEG decoder
for decoding JPEG image and Motion JPEG bitstream.
changes since v5:
- remove redundant name from struct mtk_jpeg_fmt
- Set state of all buffers to VB2_BUF_STATE_QUEUED if fail in start streaming
- Remove VB2_USERPTR
- Add check for buffer index
changes since v4:
- Change file name of binding documentation
- Revise DT binding documentation
- Revise compatible string
changes since v3:
- Revise DT binding documentation
- Revise compatible string
changes since v2:
- Revise DT binding documentation
changes since v1:
- Rebase for v4.9-rc1.
- Update Compliance test version and result
- Remove redundant path in Makefile
- Fix potential build error without CONFIG_PM_RUNTIME and CONFIG_PM_SLEEP
- Fix warnings from patch check and smatch check
* Dependency
The patch "arm: dts: mt2701: Add node for JPEG decoder" depends on:
CCF "Add clock support for Mediatek MT2701"[1]
iommu and smi "Add the dtsi node of iommu and smi for mt2701"[2]
[1] http://lists.infradead.org/pipermail/linux-mediatek/2016-October/007271.html
[2] https://patchwork.kernel.org/patch/9164013/
* Compliance test
v4l2-compliance SHA : 4ad7174b908a36c4f315e3fe2efa7e2f8a6f375a
Driver Info:
Driver name : mtk-jpeg decode
Card type : mtk-jpeg decoder
Bus info : platform:15004000.jpegdec
Driver version: 4.9.0
Capabilities : 0x84204000
Video Memory-to-Memory Multiplanar
Streaming
Extended Pix Format
Device Capabilities
Device Caps : 0x04204000
Video Memory-to-Memory Multiplanar
Streaming
Extended Pix Format
Compliance test for device /dev/video3 (not using libv4l2):
Required ioctls:
test VIDIOC_QUERYCAP: OK
Allow for multiple opens:
test second video open: OK
test VIDIOC_QUERYCAP: OK
test VIDIOC_G/S_PRIORITY: OK
test for unlimited opens: OK
Debug ioctls:
test VIDIOC_DBG_G/S_REGISTER: OK (Not Supported)
test VIDIOC_LOG_STATUS: OK (Not Supported)
Input ioctls:
test VIDIOC_G/S_TUNER/ENUM_FREQ_BANDS: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_S_HW_FREQ_SEEK: OK (Not Supported)
test VIDIOC_ENUMAUDIO: OK (Not Supported)
test VIDIOC_G/S/ENUMINPUT: OK (Not Supported)
test VIDIOC_G/S_AUDIO: OK (Not Supported)
Inputs: 0 Audio Inputs: 0 Tuners: 0
Output ioctls:
test VIDIOC_G/S_MODULATOR: OK (Not Supported)
test VIDIOC_G/S_FREQUENCY: OK (Not Supported)
test VIDIOC_ENUMAUDOUT: OK (Not Supported)
test VIDIOC_G/S/ENUMOUTPUT: OK (Not Supported)
test VIDIOC_G/S_AUDOUT: OK (Not Supported)
Outputs: 0 Audio Outputs: 0 Modulators: 0
Input/Output configuration ioctls:
test VIDIOC_ENUM/G/S/QUERY_STD: OK (Not Supported)
test VIDIOC_ENUM/G/S/QUERY_DV_TIMINGS: OK (Not Supported)
test VIDIOC_DV_TIMINGS_CAP: OK (Not Supported)
test VIDIOC_G/S_EDID: OK (Not Supported)
Control ioctls:
test VIDIOC_QUERY_EXT_CTRL/QUERYMENU: OK (Not Supported)
test VIDIOC_QUERYCTRL: OK (Not Supported)
test VIDIOC_G/S_CTRL: OK (Not Supported)
test VIDIOC_G/S/TRY_EXT_CTRLS: OK (Not Supported)
test VIDIOC_(UN)SUBSCRIBE_EVENT/DQEVENT: OK (Not Supported)
test VIDIOC_G/S_JPEGCOMP: OK (Not Supported)
Standard Controls: 0 Private Controls: 0
Format ioctls:
test VIDIOC_ENUM_FMT/FRAMESIZES/FRAMEINTERVALS: OK
test VIDIOC_G/S_PARM: OK (Not Supported)
test VIDIOC_G_FBUF: OK (Not Supported)
test VIDIOC_G_FMT: OK
test VIDIOC_TRY_FMT: OK
test VIDIOC_S_FMT: OK
test VIDIOC_G_SLICED_VBI_CAP: OK (Not Supported)
test Cropping: OK (Not Supported)
test Composing: OK
test Scaling: OK
Codec ioctls:
test VIDIOC_(TRY_)ENCODER_CMD: OK (Not Supported)
test VIDIOC_G_ENC_INDEX: OK (Not Supported)
test VIDIOC_(TRY_)DECODER_CMD: OK (Not Supported)
Buffer ioctls:
test VIDIOC_REQBUFS/CREATE_BUFS/QUERYBUF: OK
test VIDIOC_EXPBUF: OK
Test input 0:
Total: 43, Succeeded: 43, Failed: 0, Warnings: 0
Rick Chang (3):
dt-bindings: mediatek: Add a binding for Mediatek JPEG Decoder
vcodec: mediatek: Add Mediatek JPEG Decoder Driver
arm: dts: mt2701: Add node for Mediatek JPEG Decoder
.../bindings/media/mediatek-jpeg-decoder.txt | 37 +
arch/arm/boot/dts/mt2701.dtsi | 14 +
drivers/media/platform/Kconfig | 15 +
drivers/media/platform/Makefile | 2 +
drivers/media/platform/mtk-jpeg/Makefile | 2 +
drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c | 1303 ++++++++++++++++++++
drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h | 139 +++
drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c | 417 +++++++
drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h | 91 ++
drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c | 160 +++
drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h | 25 +
drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h | 58 +
12 files changed, 2263 insertions(+)
create mode 100644 Documentation/devicetree/bindings/media/mediatek-jpeg-decoder.txt
create mode 100644 drivers/media/platform/mtk-jpeg/Makefile
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_core.c
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_core.h
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.c
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_hw.h
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.c
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_parse.h
create mode 100644 drivers/media/platform/mtk-jpeg/mtk_jpeg_reg.h
--
1.9.1
^ permalink raw reply
* [PATCH v16 00/15] acpi, clocksource: add GTDT driver and GTDT support in arm_arch_timer
From: Xiongfeng Wang @ 2016-11-17 3:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1479304148-2965-1-git-send-email-fu.wei@linaro.org>
Tested-by: wangxiongfeng2 at huawei.com on D05 board.
On 2016/11/16 21:48, fu.wei at linaro.org wrote:
> From: Fu Wei <fu.wei@linaro.org>
>
> This patchset:
> (1)Preparation for adding GTDT support in arm_arch_timer:
> 1. Move some enums and marcos to header file;
> 2. Add a new enum for spi type;
> 3. Improve printk relevant code.
> 4. rename some enums and defines, and some cleanups.
> 5. separate out arch_timer_uses_ppi init code and fix a potential bug
> 6. Refactor arch_timer_detect_rate to keep dt code only in *_of_init
> 7. Refactor arch_timer_needs_probing, and call it only if acpi disabled.
> 8. Introduce some new structs and refactor the timer init code
>
> (2)Introduce ACPI GTDT parser: drivers/acpi/arm64/acpi_gtdt.c
> Parse all kinds of timer in GTDT table of ACPI:arch timer,
> memory-mapped timer and SBSA Generic Watchdog timer.
> This driver can help to simplify all the relevant timer drivers,
> and separate all the ACPI GTDT knowledge from them.
>
> (3)Simplify ACPI code for arm_arch_timer
>
> (4)Add GTDT support for ARM memory-mapped timer, also refactor
> original memory-mapped timer dt support for reusing some common
> code.
>
> This patchset has been tested on the following platforms with ACPI enabled:
> (1)ARM Foundation v8 model
>
> Changelog:
> v16: https://lkml.org/lkml/2016/
> Fix patchset problem about static enum ppi_nr of 01/13 in v15.
> Refactor arch_timer_detect_rate.
> Refactor arch_timer_needs_probing.
>
> v15: https://lkml.org/lkml/2016/11/15/366
> Re-order patches
> Add arm_arch_timer refactoring patches to prepare for GTDT:
> 1. rename some enums and defines, and some cleanups
> 2. separate out arch_timer_uses_ppi init code and fix a potential bug
> 3. Improve some new structs, refactor the timer init code.
> Since the some structs have been changed, GTDT parser for memory-mapped
> timer and SBSA Generic Watchdog timer have been update.
>
> v14: https://lkml.org/lkml/2016/9/28/573
> Separate memory-mapped timer GTDT support into two patches
> 1. Refactor the timer init code to prepare for GTDT
> 2. Add GTDT support for memory-mapped timer
>
> v13: http://www.mail-archive.com/linux-kernel at vger.kernel.org/msg1231717.html
> Improve arm_arch_timer code for memory-mapped
> timer GTDT support, refactor original memory-mapped timer
> dt support for reusing some common code.
>
> v12: https://lkml.org/lkml/2016/9/13/250
> Rebase to latest Linux 4.8-rc6
> Delete the confusing "skipping" in the error message.
>
> V11: https://lkml.org/lkml/2016/9/6/354
> Rebase to latest Linux 4.8-rc5
> Delete typedef (suggested by checkpatch.pl)
>
> V10: https://lkml.org/lkml/2016/7/26/215
> Drop the "readq" patch.
> Rebase to latest Linux 4.7.
>
> V9: https://lkml.org/lkml/2016/7/25/345
> Improve pr_err message in acpi gtdt driver.
> Update Commit message for 7/9
> shorten the irq mapping function name
> Improve GTDT driver for memory-mapped timer
>
> v8: https://lkml.org/lkml/2016/7/19/660
> Improve "pr_fmt(fmt)" definition: add "ACPI" in front of "GTDT",
> and also improve printk message.
> Simplify is_timer_block and is_watchdog.
> Merge acpi_gtdt_desc_init and gtdt_arch_timer_init into acpi_gtdt_init();
> Delete __init in include/linux/acpi.h for GTDT API
> Make ARM64 select GTDT.
> Delete "#include <linux/module.h>" from acpi_gtdt.c
> Simplify GT block parse code.
>
> v7: https://lkml.org/lkml/2016/7/13/769
> Move the GTDT driver to drivers/acpi/arm64
> Add add the ARM64-specific ACPI Support maintainers in MAINTAINERS
> Merge 3 patches of GTDT parser driver.
> Fix the for_each_platform_timer bug.
>
> v6: https://lkml.org/lkml/2016/6/29/580
> split the GTDT driver to 4 parts: basic, arch_timer, memory-mapped timer,
> and SBSA Generic Watchdog timer
> Improve driver by suggestions and example code from Daniel Lezcano
>
> v5: https://lkml.org/lkml/2016/5/24/356
> Sorting out all patches, simplify the API of GTDT driver:
> GTDT driver just fills the data struct for arm_arch_timer driver.
>
> v4: https://lists.linaro.org/pipermail/linaro-acpi/2016-March/006667.html
> Delete the kvm relevant patches
> Separate two patches for sorting out the code for arm_arch_timer.
> Improve irq info export code to allow missing irq info in GTDT table.
>
> v3: https://lkml.org/lkml/2016/2/1/658
> Improve GTDT driver code:
> (1)improve pr_* by defining pr_fmt(fmt)
> (2)simplify gtdt_sbsa_gwdt_init
> (3)improve gtdt_arch_timer_data_init, if table is NULL, it will try
> to get GTDT table.
> Move enum ppi_nr to arm_arch_timer.h, and add enum spi_nr.
> Add arm_arch_timer get ppi from DT and GTDT support for kvm.
>
> v2: https://lkml.org/lkml/2015/12/2/10
> Rebase to latest kernel version(4.4-rc3).
> Fix the bug about the config problem,
> use CONFIG_ACPI_GTDT instead of CONFIG_ACPI in arm_arch_timer.c
>
> v1: The first upstreaming version: https://lkml.org/lkml/2015/10/28/553
>
> Fu Wei (15):
> clocksource/drivers/arm_arch_timer: Move enums and defines to header
> file
> clocksource/drivers/arm_arch_timer: Add a new enum for spi type
> clocksource/drivers/arm_arch_timer: Improve printk relevant code
> clocksource/drivers/arm_arch_timer: rename some enums and defines, and
> some cleanups.
> clocksource/drivers/arm_arch_timer: fix a bug in arch_timer_register
> about arch_timer_uses_ppi
> clocksource/drivers/arm_arch_timer: separate out arch_timer_uses_ppi
> init code to prepare for GTDT.
> clocksource/drivers/arm_arch_timer: Refactor arch_timer_detect_rate to
> keep dt code in *_of_init
> clocksource/drivers/arm_arch_timer: Refactor arch_timer_needs_probing,
> and call it only if acpi disabled.
> clocksource/drivers/arm_arch_timer: Introduce some new structs to
> prepare for GTDT
> clocksource/drivers/arm_arch_timer: Refactor the timer init code to
> prepare for GTDT
> acpi/arm64: Add GTDT table parse driver
> clocksource/drivers/arm_arch_timer: Simplify ACPI support code.
> acpi/arm64: Add memory-mapped timer support in GTDT driver
> clocksource/drivers/arm_arch_timer: Add GTDT support for memory-mapped
> timer
> acpi/arm64: Add SBSA Generic Watchdog support in GTDT driver
>
> arch/arm64/Kconfig | 1 +
> drivers/acpi/arm64/Kconfig | 3 +
> drivers/acpi/arm64/Makefile | 1 +
> drivers/acpi/arm64/gtdt.c | 411 +++++++++++++++++++++++++++++
> drivers/clocksource/arm_arch_timer.c | 484 ++++++++++++++++++++---------------
> drivers/watchdog/Kconfig | 1 +
> include/clocksource/arm_arch_timer.h | 61 ++++-
> include/linux/acpi.h | 8 +
> virt/kvm/arm/hyp/timer-sr.c | 6 +-
> 9 files changed, 759 insertions(+), 217 deletions(-)
> create mode 100644 drivers/acpi/arm64/gtdt.c
>
^ permalink raw reply
* ILP32 for ARM64 - testing with lmbench
From: Zhangjian (Bamvor) @ 2016-11-17 3:28 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161028124659.GA24131@yury-N73SV>
Hi, all
I test specint of aarch64 LP64 when aarch32 el0 disable/enabled respectively
and compare with ILP32 unmerged kernel(4.8-rc6) in our arm64 board. I found
that difference(ILP32 disabled/ILP32 unmerged) is bigger when aarch32 el0 is
enabled, compare with aarch32 el0 disabled kernel. And bzip2, mcg, hmmer,
libquantum are the top four differences[1]. Note that bigger is better in
specint test.
In order to make sure the above results, I retest these four testcases in
reportable way(reference the command in the end). The result[2] show that
libquantum decrease -2.09% after ILP32 enabled and aarch32 on. I think it is in
significant.
The result of lmbench is not stable in my board. I plan to dig it later.
[1] The following test result is tested through --size=ref --iterations=3.
1.1 Test when aarch32_el0 is enabled.
ILP32 disabled base line
400.perlbench 100.00% 100%
401.bzip2 99.35% 100%
403.gcc 100.26% 100%
429.mcf 102.75% 100%
445.gobmk 100.00% 100%
456.hmmer 95.66% 100%
458.sjeng 100.00% 100%
462.libquantum 100.00% 100%
471.omnetpp 100.59% 100%
473.astar 99.66% 100%
483.xalancbmk 99.10% 100%
1.2 Test when aarch32_el0 is disabled
ILP32 disabled base line
400.perlbench 100.22% 100%
401.bzip2 100.95% 100%
403.gcc 100.20% 100%
429.mcf 100.76% 100%
445.gobmk 100.36% 100%
456.hmmer 97.94% 100%
458.sjeng 99.73% 100%
462.libquantum 98.72% 100%
471.omnetpp 100.86% 100%
473.astar 99.15% 100%
483.xalancbmk 100.08% 100%
[2] The following test result is tested through: runspec --config=my.cfg --size=test,train,ref --noreportable --tune=base,peak --iterations=3 bzip2 mcf hmmer libquantum
2.1 Test when aarch32_el0 is enabled.
ILP32_enabled base line
401.bzip2 100.82% 100%
429.mcf 100.18% 100%
456.hmmer 99.64% 100%
462.libquantum 97.91% 100%
Regards
Bamvor
On 2016/10/28 20:46, Yury Norov wrote:
> [Add Steve Ellcey, thanks for testing on ThunderX]
>
> Lmbench-3.0-a9 testing is performed on ThunderX machine to check that
> ILP32 series does not add performance regressions for LP64. Test
> summary is in the table below. Our measurements doesn't show
> significant performance regression of LP64 if ILP32 code is merged,
> both enabled or disabled.
>
> ILP32 enabled ILP32 disabled Standard Kernel
> null syscall 0.1066 0.1121 0.1121
> 95.09% 100.00%
>
> stat 1.3947 1.3814 1.3864
> 100.60% 99.64%
>
> fstat 0.4459 0.4344 0.4524
> 98.56% 96.02%
>
> open/close 4.0606 4.0411 4.0453
> 100.38% 99.90%
>
> read 0.4819 0.5014 0.5014
> 96.11% 100.00%
>
> Tested with linux 4.8 because 4.9-rc1 is not fixed yet for ThunderX.
> Other system details below.
>
> Yury.
>
> ubuntu at crb6:~$ uname -a
> Linux crb6 4.8.0+ #3 SMP Thu Oct 27 11:01:32 PDT 2016 aarch64 aarch64 aarch64 GNU/Linux
>
> ubuntu at crb6:~$ cat /proc/meminfo
> MemTotal: 132011948 kB
> MemFree: 131442672 kB
> MemAvailable: 130695764 kB
> Buffers: 15696 kB
> Cached: 88088 kB
> SwapCached: 0 kB
> Active: 82760 kB
> Inactive: 41336 kB
> Active(anon): 20880 kB
> Inactive(anon): 8576 kB
> Active(file): 61880 kB
> Inactive(file): 32760 kB
> Unevictable: 0 kB
> Mlocked: 0 kB
> SwapTotal: 128920572 kB
> SwapFree: 128920572 kB
> Dirty: 0 kB
> Writeback: 0 kB
> AnonPages: 20544 kB
> Mapped: 19780 kB
> Shmem: 9060 kB
> Slab: 78804 kB
> SReclaimable: 27372 kB
> SUnreclaim: 51432 kB
> KernelStack: 8336 kB
> PageTables: 820 kB
> NFS_Unstable: 0 kB
> Bounce: 0 kB
> WritebackTmp: 0 kB
> CommitLimit: 194926544 kB
> Committed_AS: 256324 kB
> VmallocTotal: 135290290112 kB
> VmallocUsed: 0 kB
> VmallocChunk: 0 kB
> AnonHugePages: 0 kB
> ShmemHugePages: 0 kB
> ShmemPmdMapped: 0 kB
> CmaTotal: 0 kB
> CmaFree: 0 kB
> HugePages_Total: 0
> HugePages_Free: 0
> HugePages_Rsvd: 0
> HugePages_Surp: 0
> Hugepagesize: 2048 kB
>
> ubuntu at crb6:~$ cat /proc/cpuinfo
> processor : 0
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 1
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 2
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 3
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 4
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 5
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 6
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 7
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 8
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 9
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 10
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 11
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 12
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 13
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 14
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 15
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 16
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 17
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 18
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 19
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 20
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 21
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 22
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 23
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 24
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 25
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 26
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 27
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 28
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 29
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 30
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 31
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 32
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 33
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 34
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 35
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 36
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 37
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 38
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 39
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 40
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 41
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 42
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 43
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 44
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 45
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 46
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
> processor : 47
> BogoMIPS : 200.00
> Features : fp asimd evtstrm aes pmull sha1 sha2 crc32 atomics
> CPU implementer : 0x43
> CPU architecture: 8
> CPU variant : 0x1
> CPU part : 0x0a1
> CPU revision : 0
>
^ permalink raw reply
* [PATCH v1 1/4] dt-bindings: Document Broadcom iProc mailbox controller driver
From: Jassi Brar @ 2016-11-17 3:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1476817238-1226-2-git-send-email-jonathan.richardson@broadcom.com>
On Wed, Oct 19, 2016 at 12:30 AM, Jonathan Richardson
<jonathan.richardson@broadcom.com> wrote:
> Reviewed-by: Jonathan Richardson <jonathan.richardson@broadcom.com>
> Tested-by: Jonathan Richardson <jonathan.richardson@broadcom.com>
> Reviewed-by: Vikram Prakash <vikram.prakash@broadcom.com>
> Reviewed-by: Ray Jui <ray.jui@broadcom.com>
> Reviewed-by: Shreesha Rajashekar <shreesha.rajashekar@broadcom.com>
> Reviewed-by: Scott Branden <scott.branden@broadcom.com>
> Signed-off-by: Jonathan Richardson <jonathan.richardson@broadcom.com>
> ---
Wow, heavily endorsed! :) Some log explaining the node, would have
been nice. Especially how mailbox acts as an interrupt controller.
Thanks.
^ permalink raw reply
* [PATCH 1/3] arm: hisi: add ARCH_MULTI_V5 support
From: Jiancheng Xue @ 2016-11-17 3:03 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <582C2785.2010804@hisilicon.com>
Hi Wei?
On 2016/11/16 17:31, Wei Xu wrote:
> Hi Pan,
>
> On 2016/11/16 8:56, wenpan wrote:
>> Hi Marty?
>> Does this confict with your patch? If not?I hope this could be merged first. Besides could you tell me the link to your related patch?
>
> This is the link: https://patchwork.kernel.org/patch/9334743/
>
Thank you for offering this.If I want to give some comments on Marty's patch,
what should I do?
For Marty's patch, I think there's no need to add specific config item ARCH_HIxxxx
for every chipset. Some existing chipsets depend on ARCH_HISI directly like Hi3519
and Hi3798CV200. If some options like ARM_GIC is removed from ARCH_HISI, this kind
of chipsets will must choose other place to select it. I suggest we should keep selecting
ARM_GIC under ARCH_HISI as Pan's patch do.
The code may be like this:
config ARCH_HISI
bool "Hisilicon SoC Support"
- depends on ARCH_MULTI_V7
+ depends on ARCH_MULTI_V5 || ARCH_MULTI_V6 || ARCH_MULTI_V7
select ARM_AMBA
- select ARM_GIC
+ select ARM_GIC if ARCH_MULTI_V7
+ select ARM_VIC if ARCH_MULTI_V5 || depends on ARCH_MULTI_V6
select ARM_TIMER_SP804
select POWER_RESET
select POWER_RESET_HISI
select POWER_SUPPLY
What's your opinion?
Best Regards,
Jiancheng
>> On 2016/10/17 21:48, Arnd Bergmann wrote:
>>> On Monday, October 17, 2016 8:07:03 PM CEST Pan Wen wrote:
>>>> Add support for some HiSilicon SoCs which depend on ARCH_MULTI_V5.
>>>>
>>>> Signed-off-by: Pan Wen <wenpan@hisilicon.com>
>>>>
>>>
>>> Looks ok. I've added Marty Plummer to Cc, he was recently proposing
>>> patches for Hi3520, which I think is closely related to this one.
>>> Please try to work together so the patches don't conflict. It should
>>> be fairly straightforward since you are basically doing the same
>>> change here.
>>>
^ permalink raw reply
* [PATCH 01/16] ARM: scu: Provide support for parsing SCU device node to enable SCU
From: pankaj.dubey @ 2016-11-17 2:22 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161114134813.GK1041@n2100.armlinux.org.uk>
Hi Russell,
On Monday 14 November 2016 07:18 PM, Russell King - ARM Linux wrote:
> This should be sent _to_ me because it's touching generic ARM code.
> Thanks.
>
Sorry for this.
I had included your email in CC for this patch, but looks like my email
client had some issue and this patch could not reach to your mailbox. I
will take care in future.
> On Mon, Nov 14, 2016 at 10:31:56AM +0530, Pankaj Dubey wrote:
>> Many platforms are duplicating code for enabling SCU, lets add
>> common code to enable SCU by parsing SCU device node so the duplication
>> in each platform can be avoided.
>>
>> CC: Krzysztof Kozlowski <krzk@kernel.org>
>> CC: Jisheng Zhang <jszhang@marvell.com>
>> CC: Russell King <linux@armlinux.org.uk>
>> CC: Dinh Nguyen <dinguyen@opensource.altera.com>
>> CC: Patrice Chotard <patrice.chotard@st.com>
>> CC: Linus Walleij <linus.walleij@linaro.org>
>> CC: Liviu Dudau <liviu.dudau@arm.com>
>> CC: Ray Jui <rjui@broadcom.com>
>> CC: Stephen Warren <swarren@wwwdotorg.org>
>> CC: Heiko Stuebner <heiko@sntech.de>
>> CC: Shawn Guo <shawnguo@kernel.org>
>> CC: Michal Simek <michal.simek@xilinx.com>
>> CC: Wei Xu <xuwei5@hisilicon.com>
>> CC: Andrew Lunn <andrew@lunn.ch>
>> CC: Jun Nie <jun.nie@linaro.org>
>> Suggested-by: Arnd Bergmann <arnd@arndb.de>
>> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
>> ---
>> arch/arm/include/asm/smp_scu.h | 4 +++
>> arch/arm/kernel/smp_scu.c | 56 ++++++++++++++++++++++++++++++++++++++++++
>> 2 files changed, 60 insertions(+)
>>
>> diff --git a/arch/arm/include/asm/smp_scu.h b/arch/arm/include/asm/smp_scu.h
>> index bfe163c..fdeec07 100644
>> --- a/arch/arm/include/asm/smp_scu.h
>> +++ b/arch/arm/include/asm/smp_scu.h
>> @@ -39,8 +39,12 @@ static inline int scu_power_mode(void __iomem *scu_base, unsigned int mode)
>>
>> #if defined(CONFIG_SMP) && defined(CONFIG_HAVE_ARM_SCU)
>> void scu_enable(void __iomem *scu_base);
>> +void __iomem *of_scu_get_base(void);
>> +int of_scu_enable(void);
>> #else
>> static inline void scu_enable(void __iomem *scu_base) {}
>> +static inline void __iomem *of_scu_get_base(void) {return NULL; }
>> +static inline int of_scu_enable(void) {return 0; }
>> #endif
>>
>> #endif
>> diff --git a/arch/arm/kernel/smp_scu.c b/arch/arm/kernel/smp_scu.c
>> index 72f9241..d0ac3ed 100644
>> --- a/arch/arm/kernel/smp_scu.c
>> +++ b/arch/arm/kernel/smp_scu.c
>> @@ -10,6 +10,7 @@
>> */
>> #include <linux/init.h>
>> #include <linux/io.h>
>> +#include <linux/of_address.h>
>>
>> #include <asm/smp_plat.h>
>> #include <asm/smp_scu.h>
>> @@ -70,6 +71,61 @@ void scu_enable(void __iomem *scu_base)
>> */
>> flush_cache_all();
>> }
>> +
>> +static const struct of_device_id scu_match[] = {
>> + { .compatible = "arm,cortex-a9-scu", },
>> + { .compatible = "arm,cortex-a5-scu", },
>> + { }
>> +};
>> +
>> +/*
>> + * Helper API to get SCU base address
>> + * In case platform DT do not have SCU node, or iomap fails
>> + * this call will fallback and will try to map via call to
>> + * scu_a9_get_base.
>> + * This will return ownership of scu_base to the caller
>> + */
>> +void __iomem *of_scu_get_base(void)
>> +{
>> + unsigned long base = 0;
>> + struct device_node *np;
>> + void __iomem *scu_base;
>> +
>> + np = of_find_matching_node(NULL, scu_match);
>> + scu_base = of_iomap(np, 0);
>> + of_node_put(np);
>> + if (!scu_base) {
>> + pr_err("%s failed to map scu_base via DT\n", __func__);
>> + if (scu_a9_has_base()) {
>> + base = scu_a9_get_base();
>> + scu_base = ioremap(base, SZ_4K);
>> + }
>> + if (!scu_base) {
>> + pr_err("%s failed to map scu_base\n", __func__);
>> + return IOMEM_ERR_PTR(-ENOMEM);
>
> I can't see the point of using error-pointers here - it's not like we
> really know why we're failing, so just return NULL.
>
>> + }
>> + }
>> + return scu_base;
>> +}
>> +
>> +/*
>> + * Enable SCU via mapping scu_base DT
>> + * If scu_base mapped successfully scu will be enabled and in case of
>> + * failure if will return non-zero error code
>> + */
>> +int of_scu_enable(void)
>> +{
>> + void __iomem *scu_base;
>> +
>> + scu_base = of_scu_get_base();
>> + if (!IS_ERR(scu_base)) {
>> + scu_enable(scu_base);
>> + iounmap(scu_base);
>> + return 0;
>> + }
>> + return PTR_ERR(scu_base);
>
> and just return your -ENOMEM here.
>
^ permalink raw reply
* [PATCH V8 0/6] thermal: bcm2835: add thermal driver
From: Eduardo Valentin @ 2016-11-17 2:21 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478081906-12009-1-git-send-email-kernel@martin.sperl.org>
Hello,
On Wed, Nov 02, 2016 at 10:18:20AM +0000, kernel at martin.sperl.org wrote:
> From: Martin Sperl <kernel@martin.sperl.org>
>
> Add a thermal driver for the TSENSE device of the bcm2835/6/7 SOC.
>
> If the firmware enables the HW, then the configuration is not touched.
> In case the firmware has not enabled the device, then we try to set
> it up correctly (which unfortunately can not get tested).
>
> It exposes temperature and a critical trip point
> (using a hardcoded default of 80C or the temperature configured
> in the control register by the firmware, which reads as
> 407C currently)
>
> The calibrations are (potentially) different for bcm2835, bcm2836
> and bcm2837 and can get selected by the compatible property
> in the device tree.
>
> The driver also exposes the registers via debugfs.
>
> Possible future enhancements:
> * the device has the ability to trigger interrupts on reaching
> the programmed critical temperature.
> I have no knowledge which interrupt could be responsible
> for this on the ARM side, so if we get to know which irq
> it is we can implement that.
> Instead the driver right now implements polling in 1 second intervals
> * the device can also reset the HW after the trip point
> has been reached (also with some delay, so that corrective
> actions can get taken) - this is currently not enabled by the
> firmware, but could.
> * we could define more trip points for THERMAL_TRIP_HOT
> * make the trip point limits modifiable (ops.set_trip_temp)
>
> Note:
> No support for 32-bit arm bcm2837, as there is no
> arch/arm/boot/dts/bcm2836.dtsi upstream as of now.
> 64-bit arm support is not tested
>
> Changelog:
> V1 -> V2: renamed dt-binding documentation file
> added specific settings depending on compatible
> added trip point based on register
> setting up ctrl-register if HW is not enabled by firmware
> as per recommendation of Eric (untested)
> check that clock frequency is in range
> (1.9 - 5MHz - as per comment in clk-bcm2835.c)
> added driver to multi_v7_defconfig
> V2 -> V3: made a module in multi_v7_defconfig
> fixed typo in dt-binding document
> V3 -> V4: moved driver back to thermal (not using bcm sub-directory)
> set polling interval to 1second (was 0ms, so interrupt driven)
> V4 -> V5: use correct compatiblity for different soc versions in dt
> support ARM64 for bcm2837 in devicetree and defconfig
> V5 -> V6: incorporated changes recommended by Stefan Wahren
> V6 -> V7: removed depends on ARCH_BCM2836 || ARCH_BCM2837 in Kconfig
> V7 -> V8: rebased
>
Despite the minor questions on patch 2, specially on the request to use
existing slope and offset properties, I am ok with the other DT changes.
^ permalink raw reply
* [PATCH 2/6] dt-bindings: clk: max8997: Add DT binding documentation
From: pankaj.dubey @ 2016-11-17 2:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161114161546.oitvons6tvlazgsb@rob-hp-laptop>
Hi Rob,
On Monday 14 November 2016 09:45 PM, Rob Herring wrote:
> On Mon, Nov 07, 2016 at 03:39:32PM +0530, Pankaj Dubey wrote:
>> Add Device Tree binding documentation for the clocks
>> outputs in the Maxim-8997 Power Management IC.
>>
>> CC: Michael Turquette <mturquette@baylibre.com>
>> CC: Rob Herring <robh+dt@kernel.org>
>> CC: devicetree at vger.kernel.org
>> CC: linux-clk at vger.kernel.org
>> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
>> ---
>> .../devicetree/bindings/clock/maxim,max8997.txt | 44 ++++++++++++++++++++++
>> .../bindings/regulator/max8997-regulator.txt | 3 ++
>> 2 files changed, 47 insertions(+)
>> create mode 100644 Documentation/devicetree/bindings/clock/maxim,max8997.txt
>>
>> diff --git a/Documentation/devicetree/bindings/clock/maxim,max8997.txt b/Documentation/devicetree/bindings/clock/maxim,max8997.txt
>> new file mode 100644
>> index 0000000..d2e2a74
>> --- /dev/null
>> +++ b/Documentation/devicetree/bindings/clock/maxim,max8997.txt
>> @@ -0,0 +1,44 @@
>> +Binding for Maxim MAX8997 32k clock generator block
>> +
>> +This is a part of device tree bindings of MAX8997 multi-function device.
>> +More information can be found in bindings/regulator/max8997-regulator.txt file.
>> +
>> +The MAX8997 contains two 32.768khz clock outputs that can be controlled
>> +(gated/ungated) over I2C.
>> +
>> +Following properties should be presend in main device node of the MFD chip.
>> +
>> +Required properties:
>> +
>> +- #clock-cells: from common clock binding; shall be set to 1.
>> +
>> +Optional properties:
>> +- clock-output-names: From common clock binding.
>> +
>> +Each clock is assigned an identifier and client nodes can use this identifier
>> +to specify the clock which they consume. Following indices are allowed:
>> + - 0: 32khz_ap clock,
>> + - 1: 32khz_cp clock,
>> +
>> +Clocks are defined as preprocessor macros in dt-bindings/clock/maxim,max8997.h
>> +header and can be used in device tree sources.
>> +
>> +Example: Node of the MFD chip
>> +
>> + max8997: max8997_pmic at 66 {
>
> pmic at 66 {
>
> With that:
>
> Acked-by: Rob Herring <robh@kernel.org>
>
>
Thanks for review and ack.
With above mentioned change I will post v2 soon.
Thanks,
Pankaj Dubey
^ permalink raw reply
* [PATCH 02/16] ARM: EXYNOS: use generic API to enable SCU
From: pankaj.dubey @ 2016-11-17 2:15 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20161115185939.GA14626@kozik-lap>
Hi Krzysztof,
On Wednesday 16 November 2016 12:29 AM, Krzysztof Kozlowski wrote:
> On Mon, Nov 14, 2016 at 10:31:57AM +0530, Pankaj Dubey wrote:
>> Now as we have of_scu_enable which takes care of mapping
>> scu base from DT, lets use it.
>>
>> This patch also fixes build failure in case !SMP caused
>> by commit SHA ID: 94210b1abb2 which is already merged in
>> krzk/for-next branch
>>
>> CC: Krzysztof Kozlowski <krzk@kernel.org>
>> CC: linux-samsung-soc at vger.kernel.org
>> Signed-off-by: Pankaj Dubey <pankaj.dubey@samsung.com>
>> ---
>> arch/arm/mach-exynos/common.h | 1 -
>> arch/arm/mach-exynos/platsmp.c | 30 ++++--------------------------
>> arch/arm/mach-exynos/pm.c | 4 ++--
>> arch/arm/mach-exynos/suspend.c | 14 ++++----------
>> 4 files changed, 10 insertions(+), 39 deletions(-)
>>
>
> Looks correct, for reference:
> Reviewed-by: Krzysztof Kozlowski <krzk@kernel.org>
>
Thanks for review.
> However this depends on changes in my next/soc branch (and these changes
> were the trigger for this patchset). I can either provide a tag with
> Exynos commits or accept one with common SCU code.
>
I am not sure through which tree this series need to be taken. I will
leave this to you and ARM-SOC maintainers.
As there are few comments on few patches of this series, I will address
them and soon post v2. Though I don't see any changes will be in v2 for
exynos platform. So I will include your review tag.
Thanks,
Pankaj Dubey
> Best regards,
> Krzysztof
>
>
>
^ permalink raw reply
* [PATCH 08/16] ARM: vexpress: use generic API for enabling SCU
From: pankaj.dubey @ 2016-11-17 2:12 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <c6cb4dbd-847e-832a-894b-bf8718248538@arm.com>
Hi Sudeep,
On Wednesday 16 November 2016 08:04 PM, Sudeep Holla wrote:
>
>
> On 14/11/16 05:02, Pankaj Dubey wrote:
>> Now as we have of_scu_enable which takes care of mapping
>> scu base from DT, lets use it.
>>
>> CC: Liviu Dudau <liviu.dudau@arm.com>
>> CC: Sudeep Holla <sudeep.holla@arm.com>
>
> I assume you will take this series through a single tree. Also I assume
> you may make changes around a9 SCU. I will try to test if I can get my
> setup back working. But if this patch is not changed, then
>
> Acked-by: Sudeep Holla <sudeep.holla@arm.com>
Thanks for review and Ack.
Yes, plan is to take this series through a single tree.
As there are few comments for other platforms and common scu file, I
will address them and submit v2 of this series soon. But I can see there
won't be any changes for vexpress platform patch in v2, so I will
include your Ack.
Thanks,
Pankaj Dubey
^ permalink raw reply
* [PATCH V8 2/6] thermal: bcm2835: add thermal driver for bcm2835 soc
From: Eduardo Valentin @ 2016-11-17 2:11 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1478081906-12009-3-git-send-email-kernel@martin.sperl.org>
Hey Martin,
Very sorry for the late feedback. Not so sure if this one got queued
already or not. Anyways, just minor questions as follows:
On Wed, Nov 02, 2016 at 10:18:22AM +0000, kernel at martin.sperl.org wrote:
> From: Martin Sperl <kernel@martin.sperl.org>
>
> Add basic thermal driver for bcm2835 SOC.
>
> This driver currently relies on the firmware setting up the
> tsense HW block and does not set it up itself.
>
> Signed-off-by: Martin Sperl <kernel@martin.sperl.org>
> Acked-by: Eric Anholt <eric@anholt.net>
> Acked-by: Stefan Wahren <stefan.wahren@i2se.com>
>
> ChangeLog:
> V1 -> V2: added specific settings depending on compatiblity
> added trip point based on register
> setting up ctrl-register if HW is not enabled by firmware
> as per recommendation of Eric (untested)
> check that clock frequency is in range
> (1.9 - 5MHz - as per comment in clk-bcm2835.c)
> V2 -> V4: moved back to thermal (not using bcm sub-directory)
> set polling interval to 1second (was 0ms, so interrupt driven)
> V5 -> V6: added correct depends in KConfig
> removed defined default for RESET_DELAY
> removed obvious comments
> clarify HW setup comments if not set up by FW already
> move clk_prepare_enable to an earlier stage and add error handling
> clarify warning when TS-clock runs out of recommended range
> clk_disable_unprepare added in bcm2835_thermal_remove
> added comment on recommended temperature ranges for SOC
> V6 -> V7: removed depends on ARCH_BCM2836 || ARCH_BCM2837 in Kconfig
> V7 -> V8: rebased
> ---
> drivers/thermal/Kconfig | 8 +
> drivers/thermal/Makefile | 1 +
> drivers/thermal/bcm2835_thermal.c | 340 ++++++++++++++++++++++++++++++++++++++
> 3 files changed, 349 insertions(+)
> create mode 100644 drivers/thermal/bcm2835_thermal.c
>
> diff --git a/drivers/thermal/Kconfig b/drivers/thermal/Kconfig
> index a13541b..ab946ff 100644
> --- a/drivers/thermal/Kconfig
> +++ b/drivers/thermal/Kconfig
> @@ -434,4 +434,12 @@ depends on (ARCH_QCOM && OF) || COMPILE_TEST
> source "drivers/thermal/qcom/Kconfig"
> endmenu
>
> +config BCM2835_THERMAL
> + tristate "Thermal sensors on bcm2835 SoC"
> + depends on ARCH_BCM2835 || COMPILE_TEST
> + depends on HAS_IOMEM
> + depends on OF
> + help
> + Support for thermal sensors on Broadcom bcm2835 SoCs.
> +
> endif
> diff --git a/drivers/thermal/Makefile b/drivers/thermal/Makefile
> index c92eb22..a10ebe0 100644
> --- a/drivers/thermal/Makefile
> +++ b/drivers/thermal/Makefile
> @@ -55,3 +55,4 @@ obj-$(CONFIG_TEGRA_SOCTHERM) += tegra/
> obj-$(CONFIG_HISI_THERMAL) += hisi_thermal.o
> obj-$(CONFIG_MTK_THERMAL) += mtk_thermal.o
> obj-$(CONFIG_GENERIC_ADC_THERMAL) += thermal-generic-adc.o
> +obj-$(CONFIG_BCM2835_THERMAL) += bcm2835_thermal.o
> diff --git a/drivers/thermal/bcm2835_thermal.c b/drivers/thermal/bcm2835_thermal.c
> new file mode 100644
> index 0000000..3468c7b
> --- /dev/null
> +++ b/drivers/thermal/bcm2835_thermal.c
> @@ -0,0 +1,340 @@
> +/*
> + * Driver for Broadcom BCM2835 soc temperature sensor
> + *
> + * Copyright (C) 2016 Martin Sperl
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + */
> +
> +#include <linux/clk.h>
> +#include <linux/debugfs.h>
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +#include <linux/of.h>
> +#include <linux/of_address.h>
> +#include <linux/of_device.h>
> +#include <linux/platform_device.h>
> +#include <linux/thermal.h>
> +
> +#define BCM2835_TS_TSENSCTL 0x00
> +#define BCM2835_TS_TSENSSTAT 0x04
> +
> +#define BCM2835_TS_TSENSCTL_PRWDW BIT(0)
> +#define BCM2835_TS_TSENSCTL_RSTB BIT(1)
> +#define BCM2835_TS_TSENSCTL_CTRL_BITS 3
> +#define BCM2835_TS_TSENSCTL_CTRL_SHIFT 2
> +#define BCM2835_TS_TSENSCTL_CTRL_MASK \
> + GENMASK(BCM2835_TS_TSENSCTL_CTRL_BITS + \
> + BCM2835_TS_TSENSCTL_CTRL_SHIFT - 1, \
> + BCM2835_TS_TSENSCTL_CTRL_SHIFT)
> +#define BCM2835_TS_TSENSCTL_CTRL_DEFAULT 1
> +#define BCM2835_TS_TSENSCTL_EN_INT BIT(5)
> +#define BCM2835_TS_TSENSCTL_DIRECT BIT(6)
> +#define BCM2835_TS_TSENSCTL_CLR_INT BIT(7)
> +#define BCM2835_TS_TSENSCTL_THOLD_SHIFT 8
> +#define BCM2835_TS_TSENSCTL_THOLD_BITS 10
> +#define BCM2835_TS_TSENSCTL_THOLD_MASK \
> + GENMASK(BCM2835_TS_TSENSCTL_THOLD_BITS + \
> + BCM2835_TS_TSENSCTL_THOLD_SHIFT - 1, \
> + BCM2835_TS_TSENSCTL_THOLD_SHIFT)
> +#define BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT 18
> +#define BCM2835_TS_TSENSCTL_RSTDELAY_BITS 8
> +#define BCM2835_TS_TSENSCTL_REGULEN BIT(26)
> +
> +#define BCM2835_TS_TSENSSTAT_DATA_BITS 10
> +#define BCM2835_TS_TSENSSTAT_DATA_SHIFT 0
> +#define BCM2835_TS_TSENSSTAT_DATA_MASK \
> + GENMASK(BCM2835_TS_TSENSSTAT_DATA_BITS + \
> + BCM2835_TS_TSENSSTAT_DATA_SHIFT - 1, \
> + BCM2835_TS_TSENSSTAT_DATA_SHIFT)
> +#define BCM2835_TS_TSENSSTAT_VALID BIT(10)
> +#define BCM2835_TS_TSENSSTAT_INTERRUPT BIT(11)
> +
> +struct bcm2835_thermal_info {
> + int offset;
> + int slope;
> + int trip_temp;
> +};
> +
> +struct bcm2835_thermal_data {
> + const struct bcm2835_thermal_info *info;
> + void __iomem *regs;
> + struct clk *clk;
> + struct dentry *debugfsdir;
> +};
> +
> +static int bcm2835_thermal_adc2temp(
> + const struct bcm2835_thermal_info *info, u32 adc)
> +{
> + return info->offset + (adc * info->slope);
Any specific reason we cannot use thermal_zone_params->slope and
thermal_zone_params->offset?
> +}
> +
> +static int bcm2835_thermal_temp2adc(
> + const struct bcm2835_thermal_info *info, int temp)
> +{
> + temp -= info->offset;
> + temp /= info->slope;
> +
> + if (temp < 0)
> + temp = 0;
> + if (temp >= BIT(BCM2835_TS_TSENSSTAT_DATA_BITS))
> + temp = BIT(BCM2835_TS_TSENSSTAT_DATA_BITS) - 1;
> +
> + return temp;
> +}
> +
> +static int bcm2835_thermal_get_trip_type(
> + struct thermal_zone_device *tz, int trip,
> + enum thermal_trip_type *type)
> +{
> + *type = THERMAL_TRIP_CRITICAL;
> + return 0;
> +}
> +
> +static int bcm2835_thermal_get_trip_temp(
> + struct thermal_zone_device *tz, int trip, int *temp)
> +{
> + struct bcm2835_thermal_data *data = tz->devdata;
> + u32 val = readl(data->regs + BCM2835_TS_TSENSCTL);
> +
> + /* get the THOLD bits */
> + val &= BCM2835_TS_TSENSCTL_THOLD_MASK;
> + val >>= BCM2835_TS_TSENSCTL_THOLD_SHIFT;
> +
> + /* if it is zero then use the info value */
> + if (val)
Is this a read only register or is this driver supposed to program it?
In which scenario it would be 0? Can this be added as comments?
> + *temp = bcm2835_thermal_adc2temp(data->info, val);
> + else
> + *temp = data->info->trip_temp;
> +
> + return 0;
> +}
> +
> +static int bcm2835_thermal_get_temp(struct thermal_zone_device *tz,
> + int *temp)
> +{
> + struct bcm2835_thermal_data *data = tz->devdata;
> + u32 val = readl(data->regs + BCM2835_TS_TSENSSTAT);
> +
> + if (!(val & BCM2835_TS_TSENSSTAT_VALID))
What cases you would get the valid bit not set? Do you need to wait for
the conversion to finish?
> + return -EIO;
> +
> + val &= BCM2835_TS_TSENSSTAT_DATA_MASK;
> +
> + *temp = bcm2835_thermal_adc2temp(data->info, val);
> +
> + return 0;
> +}
> +
> +static const struct debugfs_reg32 bcm2835_thermal_regs[] = {
> + {
> + .name = "ctl",
> + .offset = 0
> + },
> + {
> + .name = "stat",
> + .offset = 4
> + }
> +};
> +
> +static void bcm2835_thermal_debugfs(struct platform_device *pdev)
> +{
> + struct thermal_zone_device *tz = platform_get_drvdata(pdev);
> + struct bcm2835_thermal_data *data = tz->devdata;
> + struct debugfs_regset32 *regset;
> +
> + data->debugfsdir = debugfs_create_dir("bcm2835_thermal", NULL);
> + if (!data->debugfsdir)
> + return;
> +
> + regset = devm_kzalloc(&pdev->dev, sizeof(*regset), GFP_KERNEL);
> + if (!regset)
> + return;
> +
> + regset->regs = bcm2835_thermal_regs;
> + regset->nregs = ARRAY_SIZE(bcm2835_thermal_regs);
> + regset->base = data->regs;
> +
> + debugfs_create_regset32("regset", S_IRUGO,
> + data->debugfsdir, regset);
> +}
> +
> +static struct thermal_zone_device_ops bcm2835_thermal_ops = {
> + .get_temp = bcm2835_thermal_get_temp,
> + .get_trip_temp = bcm2835_thermal_get_trip_temp,
> + .get_trip_type = bcm2835_thermal_get_trip_type,
> +};
> +
> +static const struct of_device_id bcm2835_thermal_of_match_table[];
> +static int bcm2835_thermal_probe(struct platform_device *pdev)
> +{
> + const struct of_device_id *match;
> + struct thermal_zone_device *tz;
> + struct bcm2835_thermal_data *data;
> + struct resource *res;
> + int err;
> + u32 val;
> + unsigned long rate;
> +
> + data = devm_kzalloc(&pdev->dev, sizeof(*data), GFP_KERNEL);
> + if (!data)
> + return -ENOMEM;
> +
> + match = of_match_device(bcm2835_thermal_of_match_table,
> + &pdev->dev);
> + if (!match)
> + return -EINVAL;
> + data->info = match->data;
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + data->regs = devm_ioremap_resource(&pdev->dev, res);
> + if (IS_ERR(data->regs)) {
> + err = PTR_ERR(data->regs);
> + dev_err(&pdev->dev, "Could not get registers: %d\n", err);
> + return err;
> + }
> +
> + data->clk = devm_clk_get(&pdev->dev, NULL);
> + if (IS_ERR(data->clk)) {
> + err = PTR_ERR(data->clk);
> + if (err != -EPROBE_DEFER)
> + dev_err(&pdev->dev, "Could not get clk: %d\n", err);
> + return err;
> + }
> +
> + err = clk_prepare_enable(data->clk);
> + if (err)
> + return err;
> +
> + rate = clk_get_rate(data->clk);
> + if ((rate < 1920000) || (rate > 5000000))
> + dev_warn(&pdev->dev,
> + "Clock %pCn running at %pCr Hz is outside of the recommended range: 1.92 to 5MHz\n",
> + data->clk, data->clk);
> +
> + /*
> + * right now the FW does set up the HW-block, so we are not
> + * touching the configuration registers.
> + * But if the HW is not enabled, then set it up
> + * using "sane" values used by the firmware right now.
> + */
> + val = readl(data->regs + BCM2835_TS_TSENSCTL);
> + if (!(val & BCM2835_TS_TSENSCTL_RSTB)) {
> + /* the basic required flags */
> + val = (BCM2835_TS_TSENSCTL_CTRL_DEFAULT <<
> + BCM2835_TS_TSENSCTL_CTRL_SHIFT) |
> + BCM2835_TS_TSENSCTL_REGULEN;
> +
> + /*
> + * reset delay using the current firmware value of 14
> + * - units of time are unknown.
> + */
> + val |= (14 << BCM2835_TS_TSENSCTL_RSTDELAY_SHIFT);
> +
> + /* trip_adc value from info */
> + val |= bcm2835_thermal_temp2adc(data->info,
> + data->info->trip_temp) <<
> + BCM2835_TS_TSENSCTL_THOLD_SHIFT;
> +
> + /* write the value back to the register as 2 steps */
> + writel(val, data->regs + BCM2835_TS_TSENSCTL);
> + val |= BCM2835_TS_TSENSCTL_RSTB;
> + writel(val, data->regs + BCM2835_TS_TSENSCTL);
> + }
> +
> + /* register thermal zone with 1 trip point an 1s polling */
> + tz = thermal_zone_device_register("bcm2835_thermal",
> + 1, 0, data,
> + &bcm2835_thermal_ops,
> + NULL,
> + 0, 1000);
> + if (IS_ERR(tz)) {
> + clk_disable_unprepare(data->clk);
> + err = PTR_ERR(tz);
> + dev_err(&pdev->dev,
> + "Failed to register the thermal device: %d\n",
> + err);
> + return err;
> + }
> +
> + platform_set_drvdata(pdev, tz);
> +
> + bcm2835_thermal_debugfs(pdev);
> +
> + return 0;
> +}
> +
> +static int bcm2835_thermal_remove(struct platform_device *pdev)
> +{
> + struct thermal_zone_device *tz = platform_get_drvdata(pdev);
> + struct bcm2835_thermal_data *data = tz->devdata;
> +
> + debugfs_remove_recursive(data->debugfsdir);
> + thermal_zone_device_unregister(tz);
> + clk_disable_unprepare(data->clk);
> +
> + return 0;
> +}
> +
> +/*
> + * Note: as per Raspberry Foundation FAQ
> + * (https://www.raspberrypi.org/help/faqs/#performanceOperatingTemperature)
> + * the recommended temperature range for the SOC -40C to +85C
> + * so the trip limit is set to 80C.
> + * this applies to all the BCM283X SOC
> + */
> +
> +static const struct of_device_id bcm2835_thermal_of_match_table[] = {
> + {
> + .compatible = "brcm,bcm2835-thermal",
> + .data = &(struct bcm2835_thermal_info) {
> + .offset = 407000,
> + .slope = -538,
> + .trip_temp = 80000
> + }
> + },
> + {
> + .compatible = "brcm,bcm2836-thermal",
> + .data = &(struct bcm2835_thermal_info) {
> + .offset = 407000,
> + .slope = -538,
> + .trip_temp = 80000
> + }
> + },
> + {
> + .compatible = "brcm,bcm2837-thermal",
> + .data = &(struct bcm2835_thermal_info) {
> + /* the bcm2837 needs adjustment of +5C */
> + .offset = 407000 + 5000,
> + .slope = -538,
> + .trip_temp = 80000
> + }
> + },
> + {},
> +};
> +MODULE_DEVICE_TABLE(of, bcm2835_thermal_of_match_table);
> +
> +static struct platform_driver bcm2835_thermal_driver = {
> + .probe = bcm2835_thermal_probe,
> + .remove = bcm2835_thermal_remove,
> + .driver = {
> + .name = "bcm2835_thermal",
> + .of_match_table = bcm2835_thermal_of_match_table,
> + },
> +};
> +module_platform_driver(bcm2835_thermal_driver);
> +
> +MODULE_AUTHOR("Martin Sperl");
> +MODULE_DESCRIPTION("Thermal driver for bcm2835 chip");
> +MODULE_LICENSE("GPL");
> --
> 2.1.4
^ permalink raw reply
* [PATCH] ARM: dts: lpc435x: remove address and size cells from gpio-keys-polled nodes
From: Vladimir Zapolskiy @ 2016-11-17 2:06 UTC (permalink / raw)
To: linux-arm-kernel
The change removes redundant #address-cells and #size-cells properties from
gpio-keys-polled compatible device nodes found in lpc4357-ea4357-devkit and
lpc4350-hitex-eval board DTS files.
Signed-off-by: Vladimir Zapolskiy <vz@mleia.com>
---
arch/arm/boot/dts/lpc4350-hitex-eval.dts | 2 --
arch/arm/boot/dts/lpc4357-ea4357-devkit.dts | 2 --
2 files changed, 4 deletions(-)
diff --git a/arch/arm/boot/dts/lpc4350-hitex-eval.dts b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
index 874c75d..7649285 100644
--- a/arch/arm/boot/dts/lpc4350-hitex-eval.dts
+++ b/arch/arm/boot/dts/lpc4350-hitex-eval.dts
@@ -40,8 +40,6 @@
pca_buttons {
compatible = "gpio-keys-polled";
- #address-cells = <1>;
- #size-cells = <0>;
poll-interval = <100>;
autorepeat;
diff --git a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
index 9b5fad6..50ee2d5 100644
--- a/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
+++ b/arch/arm/boot/dts/lpc4357-ea4357-devkit.dts
@@ -57,8 +57,6 @@
compatible = "gpio-keys-polled";
pinctrl-names = "default";
pinctrl-0 = <&gpio_joystick_pins>;
- #address-cells = <1>;
- #size-cells = <0>;
poll-interval = <100>;
autorepeat;
--
2.10.2
^ permalink raw reply related
* [PATCH v2 2/3] soc: rockchip: add driver handling grf setup
From: Shawn Lin @ 2016-11-17 1:38 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <5037506.GEHFh4fruS@phil>
Hi Heiko,
? 2016/11/16 17:58, Heiko Stuebner ??:
> Hi Shawn,
>
> Am Mittwoch, 16. November 2016, 17:33:21 CET schrieb Shawn Lin:
>> ? 2016/11/16 6:38, Heiko Stuebner ??:
>>> The General Register Files are an area of registers containing a lot
>>> of single-bit settings for numerous components as well full components
>>> like usbphy control. Therefore all used components are accessed
>>> via the syscon provided by the grf nodes or from the sub-devices
>>> created through the simple-mfd created from the grf node.
>>>
----8<----------------
[...]
>>> + for (i = 0; i < grf_info->num_values; i++) {
>>> + const struct rockchip_grf_value *val = &grf_info->values[i];
>>> +
>>> + pr_debug("%s: adjusting %s in %#6x to %#10x\n", __func__,
>>> + val->desc, val->reg, val->val);
>>> + ret = regmap_write(grf, val->reg, val->val);
>>> + if (ret < 0)
>>> + pr_err("%s: write to %#6x failed with %d\n",
>>> + __func__, val->reg, ret);
>>
>> So, when failing to do one of the settings, should we still let it goes?
>> Sometimes the log of postcore_initcall is easy to be neglected when
>> people finally find problems later but the very earlier log was missing
>> due to whatever reason like buffer limitation, etc.
>
> I expect errors here to be very rare. I.e. Doug thought that regmap might
> return errors if we write outside the mapped region, which would mean someone
> really messed up in this core component or a core-element of the dts.
> But in general the GRF is always a mmio-regmap, so there won't be any i2c/spi/
> whatever errors possible.
I was just thinking about the scalability that in the future some of the
GRF settings may depend on genpd or clock even if they are only a
mmio-regmap but they don't belong to the general pd/clock for GRF, for
instance, some of the PHYs' or controller's cap(like emmc) settings.
But, IIRC, you suggested this driver shouldn't be a catchall, and we
now ask the drivers of controllers and phys to take over this, so I
guess we won't put those settings here ever. :)
Thanks for explaining this.
>
> Also settings are pretty individual, so if setting 1 fails, setting 2 can
> still succeed and the boot can continue somewhat farther.
>
sure
> The overall target is supposed to always boot as far as possible, so that
> people might recover or get more information and not fail (and die) early.
>
ok, got it.
>
> Heiko
>
>
>
--
Best Regards
Shawn Lin
^ permalink raw reply
* [PATCH] ARM: dt: imx31: fix AVIC base address
From: Vladimir Zapolskiy @ 2016-11-17 1:30 UTC (permalink / raw)
To: linux-arm-kernel
From: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
On i.MX31 AVIC interrupt controller base address is at 0x68000000.
The problem was shadowed by the AVIC driver, which takes the correct
base address from a SoC specific header file.
Fixes: d2a37b3d91f4 ("ARM i.MX31: Add devicetree support")
Signed-off-by: Vladimir Zapolskiy <vladimir_zapolskiy@mentor.com>
---
arch/arm/boot/dts/imx31.dtsi | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/arch/arm/boot/dts/imx31.dtsi b/arch/arm/boot/dts/imx31.dtsi
index c534c1f..179335b 100644
--- a/arch/arm/boot/dts/imx31.dtsi
+++ b/arch/arm/boot/dts/imx31.dtsi
@@ -31,11 +31,11 @@
};
};
- avic: avic-interrupt-controller at 60000000 {
+ avic: interrupt-controller at 68000000 {
compatible = "fsl,imx31-avic", "fsl,avic";
interrupt-controller;
#interrupt-cells = <1>;
- reg = <0x60000000 0x100000>;
+ reg = <0x68000000 0x100000>;
};
soc {
--
2.10.2
^ permalink raw reply related
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox