Linux-ARM-Kernel Archive on lore.kernel.org
 help / color / mirror / Atom feed
* [PATCH] KVM: arm/arm64: fix unaligned hva start and end in handle_hva_to_gpa
From: Jia He @ 2018-05-15  2:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <695beacb-ff51-bb2c-72ef-d268f7d4e59d@arm.com>

Hi Suzuki

I will merge the other thread into this, and add the necessary CC list

That WARN_ON call trace is very easy to reproduce in my armv8a server after I 
start 20 guests

and run memhog in the host. Of course, ksm should be enabled

For you question about my inject fault debug patch:

diff --git a/mm/ksm.c b/mm/ksm.c
index e3cbf9a..876bec8 100644
--- a/mm/ksm.c
+++ b/mm/ksm.c
@@ -43,6 +43,8 @@
 ?#include <asm/tlbflush.h>
 ?#include "internal.h"

+int trigger_by_ksm = 0;
+
 ?#ifdef CONFIG_NUMA
 ?#define NUMA(x)??????????????? (x)
 ?#define DO_NUMA(x)???? do { (x); } while (0)
@@ -2587,11 +2589,14 @@ void rmap_walk_ksm(struct page *page, struct 
rmap_walk_control *rwc)
 ??????????????????????? if (rwc->invalid_vma && rwc->invalid_vma(vma, rwc->arg))
 ??????????????????????????????? continue;

+trigger_by_ksm = 1;
 ??????????????????????? if (!rwc->rmap_one(page, vma,
 ??????????????????????????????????????? rmap_item->address, rwc->arg)) {
 ??????????????????????????????? anon_vma_unlock_read(anon_vma);
+trigger_by_ksm = 0;
 ??????????????????????????????? return;
 ??????????????????????? }
+trigger_by_ksm = 0;
 ??????????????????????? if (rwc->done && rwc->done(page)) {
 ??????????????????????????????? anon_vma_unlock_read(anon_vma);
 ??????????????????????????????? return;
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 7f6a944..ab8545e 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -290,12 +290,17 @@ static void unmap_stage2_puds(struct kvm *kvm, pgd_t *pgd,
 ? * destroying the VM), otherwise another faulting VCPU may come in and mess
 ? * with things behind our backs.
 ? */
+extern int trigger_by_ksm;
 ?static void unmap_stage2_range(struct kvm *kvm, phys_addr_t start, u64 size)
 ?{
 ??????? pgd_t *pgd;
 ??????? phys_addr_t addr = start, end = start + size;
 ??????? phys_addr_t next;

+?????? if(trigger_by_ksm) {
+?????????????? end -= 0x200;
+?????? }
+
 ??????? assert_spin_locked(&kvm->mmu_lock);
 ??????? pgd = kvm->arch.pgd + stage2_pgd_index(addr);
 ??????? do {

I need to point out that I never reproduced it without this debugging patch.

Please also see my comments below

On 5/14/2018 6:06 PM, Suzuki K Poulose Wrote:
> On 14/05/18 03:30, Jia He wrote:
>>
>> On 5/11/2018 9:39 PM, Suzuki K Poulose Wrote:
>>> Marc
>>>
>>> Thanks for looping me in. Comments below.
>>>
>>>
>>> On 03/05/18 03:02, Jia He wrote:
>>>> Hi Marc
>>>>
>>>> Thanks for the review
>>>>
>>>>
>>>> On 5/2/2018 10:26 PM, Marc Zyngier Wrote:
>>>>> [+ Suzuki]
>>>>>
>>>>> On 02/05/18 08:08, Jia He wrote:
>>>>>> From: Jia He <jia.he@hxt-semitech.com>
>>>>>>
>>>>>> In our armv8a server (QDF2400), I noticed a WARN_ON as follows:
>>>>>>
>>>>>> [? 800.202850] WARNING: CPU: 33 PID: 255 at arch/arm64/kvm/../../../virt/kvm/arm/mmu.c:1670 kvm_age_hva_handler+0xcc/0xd4
>>>>> Which kernel version is that? I don't have a WARN_ON() at this line in
>>>>> 4.17. Do you have a reproducer?
>>>> My running kernel version is v4.14-15, but I can reproduced it in 4.17 (start 20 guests and run memhog in the host)
>>>> In 4.17, the warn_on is at
>>>> https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/tree/virt/kvm/arm/mmu.c#n1826
>>>>>> [? 800.213535] Modules linked in: vhost_net vhost tap xt_CHECKSUM ipt_MASQUERADE nf_nat_masquerade_ipv4 ip6t_rpfilter ipt_REJECT nf_reject_ipv4 ip6t_REJECT nf_reject_ipv6 xt_conntrack ip_set nfnetlink ebtable_nat ebtable_broute bridge stp llc ip6table_nat nf_conntrack_ipv6 nf_defrag_ipv6 nf_nat_ipv6 ip6table_mangle ip6table_security ip6table_raw iptable_nat nf_conntrack_ipv4 nf_defrag_ipv4 nf_nat_ipv4 nf_nat nf_conntrack iptable_mangle iptable_security iptable_raw ebtable_filter ebtables ip6table_filter ip6_tables iptable_filter rpcrdma ib_isert iscsi_target_mod ib_iser libiscsi scsi_transport_iscsi ib_srpt target_core_mod ib_srp scsi_transport_srp ib_ipoib rdma_ucm ib_ucm ib_uverbs ib_umad rdma_cm ib_cm vfat fat iw_cm mlx5_ib ib_core dm_mirror dm_region_hash dm_log dm_mod crc32_ce ipmi_ssif sg nfsd
>>>>>> [? 800.284115]? auth_rpcgss nfs_acl lockd grace sunrpc ip_tables xfs libcrc32c mlx5_core ixgbe mlxfw devlink mdio ahci_platform libahci_platform qcom_emac libahci hdma hdma_mgmt i2c_qup
>>>>>> [? 800.300382] CPU: 33 PID: 255 Comm: khugepaged Tainted: G??????? W?????? 4.14.36+ #6
>>>>>> [? 800.308030] Hardware name: <snip for confidential issues>
>>>>> Well, that's QDF2400, right? ;-)
>>>> yes, exactly :)
>>>>>> [? 800.318717] task: ffff8017c949c000 task.stack: ffff8017c9498000
>>>>>> [? 800.324629] PC is at kvm_age_hva_handler+0xcc/0xd4
>>>>>> [? 800.329412] LR is at handle_hva_to_gpa+0xec/0x15c
>>>>>> [? 800.334109] pc : [<ffff0000080b4f2c>] lr : [<ffff0000080b4838>] pstate: 20400145
>>>>>> [? 800.341496] sp : ffff8017c949b260
>>>>>> [? 800.344804] x29: ffff8017c949b260 x28: ffff801663e25008
>>>>>> [? 800.350110] x27: 0000000000020000 x26: 00000001fb1a0000
>>>>>> [? 800.355416] x25: 0000ffff605b0200 x24: 0000ffff605a0200
>>>>>> [? 800.360722] x23: 0000000000000000 x22: 000000000000ffff
>>>>>> [? 800.366028] x21: 00000001fb1a0000 x20: ffff8017c085a000
>>>>>> [? 800.371334] x19: ffff801663e20008 x18: 0000000000000000
>>>>>> [? 800.376641] x17: 0000000000000000 x16: 0000000000000000
>>>>>> [? 800.381947] x15: 0000000000000000 x14: 3d646e655f617668
>>>>>> [? 800.387254] x13: 2c30303230623530 x12: 36666666663d646e
>>>>>> [? 800.392560] x11: 652c303032306135 x10: 3036666666663d74
>>>>>> [? 800.397867] x9 : 0000000000003796 x8 : 655f6e66672c3030
>>>>>> [? 800.403173] x7 : ffff00000859434c x6 : ffff8017f9c30cb8
>>>>>> [? 800.408479] x5 : ffff8017f9c30cb8 x4 : ffff0000080b4e60
>>>>>> [? 800.413786] x3 : 0000000000000000 x2 : 0000000000020000
>>>>>> [? 800.419092] x1 : 00000001fb1a0000 x0 : 0000000020000000
>>>>>> [? 800.424398] Call trace:
>>>>>> [? 800.426838] Exception stack(0xffff8017c949b120 to 0xffff8017c949b260)
>>>>>> [? 800.433272] b120: 0000000020000000 00000001fb1a0000 0000000000020000 0000000000000000
>>>>>> [? 800.441095] b140: ffff0000080b4e60 ffff8017f9c30cb8 ffff8017f9c30cb8 ffff00000859434c
>>>>>> [? 800.448918] b160: 655f6e66672c3030 0000000000003796 3036666666663d74 652c303032306135
>>>>>> [? 800.456740] b180: 36666666663d646e 2c30303230623530 3d646e655f617668 0000000000000000
>>>>>> [? 800.464563] b1a0: 0000000000000000 0000000000000000 0000000000000000 ffff801663e20008
>>>>>> [? 800.472385] b1c0: ffff8017c085a000 00000001fb1a0000 000000000000ffff 0000000000000000
>>>>>> [? 800.480208] b1e0: 0000ffff605a0200 0000ffff605b0200 00000001fb1a0000 0000000000020000
>>>>>> [? 800.488030] b200: ffff801663e25008 ffff8017c949b260 ffff0000080b4838 ffff8017c949b260
>>>>>> [? 800.495853] b220: ffff0000080b4f2c 0000000020400145 0000000000000001 ffff8017c949b2a0
>>>>>> [? 800.503676] b240: ffffffffffffffff ffff8017c949b260 ffff8017c949b260 ffff0000080b4f2c
>>>>>> [? 800.511498] [<ffff0000080b4f2c>] kvm_age_hva_handler+0xcc/0xd4
>>>>>> [? 800.517324] [<ffff0000080b4838>] handle_hva_to_gpa+0xec/0x15c
>>>>>> [? 800.523063] [<ffff0000080b6c5c>] kvm_age_hva+0x5c/0xcc
>>>>>> [? 800.528194] [<ffff0000080a7c3c>] kvm_mmu_notifier_clear_flush_young+0x54/0x90
>>>>>> [? 800.535324] [<ffff00000827a0e8>] __mmu_notifier_clear_flush_young+0x6c/0xa8
>>>>>> [? 800.542279] [<ffff00000825a644>] page_referenced_one+0x1e0/0x1fc
>>>>>> [? 800.548279] [<ffff00000827e8f8>] rmap_walk_ksm+0x124/0x1a0
>>>>>> [? 800.553759] [<ffff00000825c974>] rmap_walk+0x94/0x98
>>>>>> [? 800.558717] [<ffff00000825ca98>] page_referenced+0x120/0x180
>>>>>> [? 800.564369] [<ffff000008228c58>] shrink_active_list+0x218/0x4a4
>>>>>> [? 800.570281] [<ffff000008229470>] shrink_node_memcg+0x58c/0x6fc
>>>>>> [? 800.576107] [<ffff0000082296c4>] shrink_node+0xe4/0x328
>>>>>> [? 800.581325] [<ffff000008229c9c>] do_try_to_free_pages+0xe4/0x3b8
>>>>>> [? 800.587324] [<ffff00000822a094>] try_to_free_pages+0x124/0x234
>>>>>> [? 800.593150] [<ffff000008216aa0>] __alloc_pages_nodemask+0x564/0xf7c
>>>>>> [? 800.599412] [<ffff000008292814>] khugepaged_alloc_page+0x38/0xb8
>>>>>> [? 800.605411] [<ffff0000082933bc>] collapse_huge_page+0x74/0xd70
>>>>>> [? 800.611238] [<ffff00000829470c>] khugepaged_scan_mm_slot+0x654/0xa98
>>>>>> [? 800.617585] [<ffff000008294e0c>] khugepaged+0x2bc/0x49c
>>>>>> [? 800.622803] [<ffff0000080ffb70>] kthread+0x124/0x150
>>>>>> [? 800.627762] [<ffff0000080849f0>] ret_from_fork+0x10/0x1c
>>>>>> [? 800.633066] ---[ end trace 944c130b5252fb01 ]---
>>>>>> -------------------------------------------------------------------------
>>>>>>
>>>>>> The root cause might be: we can't guarantee that the parameter start and end
>>>>>> in handle_hva_to_gpa is PAGE_SIZE aligned, let alone hva_start and hva_end.
>>>>> So why not aligning them the first place?
>>>> at the first place of handle_hva_to_gpa()?
>>>> but boundary check is needed in each loop of kvm_for_each_memslot. Am I missing anything here?
>>>>>> This bug is introduced by commit 056aad67f836 ("kvm: arm/arm64: Rework gpa
>>>>>> callback handlers")
>>>>>>
>>>>>> It fixes the bug by use pfn size converted.
>>>>>>
>>>>>> Fixes: 056aad67f836 ("kvm: arm/arm64: Rework gpa callback handlers")
>>>>>>
>>>>>> Signed-off-by: jia.he at hxt-semitech.com
>>>>>> Signed-off-by: li.zhang at hxt-semitech.com
>>>>>> ---
>>>>>>  ?? virt/kvm/arm/mmu.c | 10 ++++++----
>>>>>>  ?? 1 file changed, 6 insertions(+), 4 deletions(-)
>>>>>>
>>>>>> diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
>>>>>> index 7f6a944..9dd7ae4 100644
>>>>>> --- a/virt/kvm/arm/mmu.c
>>>>>> +++ b/virt/kvm/arm/mmu.c
>>>>>> @@ -1744,7 +1744,7 @@ static int handle_hva_to_gpa(struct kvm *kvm,
>>>>>>  ?????? /* we only care about the pages that the guest sees */
>>>>>>  ?????? kvm_for_each_memslot(memslot, slots) {
>>>>>>  ?????????? unsigned long hva_start, hva_end;
>>>>>> -??????? gfn_t gpa;
>>>>>> +??????? gpa_t gpa, gpa_end;
>>>>>>  ?????????? hva_start = max(start, memslot->userspace_addr);
>>>>>>  ?????????? hva_end = min(end, memslot->userspace_addr +
>>>>>> @@ -1753,7 +1753,9 @@ static int handle_hva_to_gpa(struct kvm *kvm,
>>>>>>  ?????????????? continue;
>>>>>>  ?????????? gpa = hva_to_gfn_memslot(hva_start, memslot) << PAGE_SHIFT;
>>>>>> -??????? ret |= handler(kvm, gpa, (u64)(hva_end - hva_start), data);
>>>>>> +??????? gpa_end = hva_to_gfn_memslot(hva_end + PAGE_SIZE - 1, memslot)
>>>>>> +???????????????????????????? << PAGE_SHIFT;
>>>>>> +??????? ret |= handler(kvm, gpa, (u64)(gpa_end - gpa), data);
>>>>> But we're looking for the mapping in the same memslot, so the distance
>>>>> between hva and hva_end is the same as the one between gpa and gpa_end
>>>>> if you didn't align it.
>>>> maybe not, sometimes hva_end-hva != gpa_end-gpa
>>>> start=fffdc37f0200,hva_start=fffdc37f0200,end=fffdc3800200,hva_end=fffdc3800000,gpa=3ff0000,gfn_end=4000000
>>>>
>>>> but sometimes it is:
>>>> start=ffff60590200,hva_start=ffff60590200,end=ffff605a0200,hva_end=ffff605a0200,gpa=1fb190000,gfn_end=1fb1b0000
>>>>
>>>> IMO, the unalignment is caused by the ksm stable page flag STABLE_FLAG. I will
>>>> propose another ksm patch to fix it?
>>>> But from handle_hva_to_gpa's point of view, arm kvm needs to void the followup
>>>> exception, just like what powerpc andx86 have done.
>>>
>>> As far as I can see this is triggered by someone (in this page_referenced_one via ksm?)
>>> triggering a clear_flush_young for a page, with a non-aligned page address.
>>>
>>> If you look at the code path, the __mmu_notifier_clear_flush_young is invoked
>>> via 2 code paths with the "given" address.
>>>
>>> ptep_clear_flush_young_notify(), in which case the end is set to + PAGE_SIZE
>>> pmdp_clear_flush_young_notify(), in which case the end is set to + PMD_SIZE
>>>
>>> We were supposed to only clear_flush_young for *the page* containing
>>> address (start), but we do a clear_flush_young for the next page
>>> as well, which (I think) is not something intended. So to me, it looks like, either
>>> page_referenced_one() or its caller must align the address to the PAGE_SIZE
>>> or PMD_SIZE depending on what it really wants to do, to avoid touching
>>> the adjacent entries (page or block pages).
>>>
>>> Suzuki
> Jia He,
>
>> Suzuki, thanks for the comments.
>>
>> I proposed another ksm patch https://lkml.org/lkml/2018/5/3/1042
>> The root cause is ksm will add some extra flags to indicate that the page
>> is in/not_in the stable tree. This makes address not be aligned with PAGE_SIZE.
> Thanks for the pointer. In the future, please Cc the people relevant to the
> discussion in the patches.
>
>>   From arm kvm mmu point of view, do you think handle_hva_to_gpa still need to handle
>> the unalignment case?
> I don't think we should do that. Had we done this, we would never have caught this bug
> in KSM. Eventually if some other new implementation comes up with the a new notifier
> consumer which doesn't check alignment and doesn't WARN, it could simply do the wrong
> thing. So I believe what we have is a good measure to make sure that things are
> in the right order.
>
>> IMO, the PAGE_SIZE alignment is still needed because we should not let the bottom function
>> kvm_age_hva_handler to handle the exception. Please refer to the implementation in X86 and
>> powerpc kvm_handle_hva_range(). They both aligned the hva with hva_to_gfn_memslot.
>>
>   From an API perspective, you are passed on a "start" and "end" address. So, you could potentially
> do the wrong thing if you align the "start" and "end". May be those handlers should also do the
> same thing as we do.
But handle_hva_to_gpa has partially adjusted the alignment possibly:
 ?? 1750???????? kvm_for_each_memslot(memslot, slots) {
 ?? 1751???????????????? unsigned long hva_start, hva_end;
 ?? 1752???????????????? gfn_t gpa;
 ?? 1753
 ?? 1754???????????????? hva_start = max(start, memslot->userspace_addr);
 ?? 1755???????????????? hva_end = min(end, memslot->userspace_addr +
 ?? 1756???????????????????????????? (memslot->npages << PAGE_SHIFT));

at line 1755, let us assume that end=0x12340200 and
memslot->userspace_addr + (memslot->npages << PAGE_SHIFT)=0x12340000
Then, hva_start is not page_size aligned and hva_end is aligned, and the size 
will be PAGE_SIZE-0x200,
just as what I had done in the inject fault debugging patch.

-- 
Cheers,
Jia

^ permalink raw reply related

* [GIT PULL] arm64: dts: hisilicon dts updates for v4.18
From: Leo Yan @ 2018-05-15  1:51 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180514200956.jzvglfib3kgjf6xs@localhost>

Hi Olof,

On Mon, May 14, 2018 at 01:09:56PM -0700, Olof Johansson wrote:

[...]

> > Leo Yan (1):
> >       dts: arm64: hi3660: Add CPU frequency scaling support
> > Tao Wang (1):
> >       dts: arm64: hi3660: Add thermal cooling management

> We try to use a very consistent patch prefix format on device tree changes to
> make it easier to get an overview, and you're unfortunately a bit inconsistent
> here.
> 
> Would you mind respinning this with "arm64: dts: hi<...>:" as the consistent
> prefix please?

Sorry for this, I should take care for this ahead.  Will respin the
patch series and send them out ASAP.

Thanks,
Leo Yan

^ permalink raw reply

* [PATCH 07/11] driver core: Respect all error codes from dev_pm_domain_attach()
From: Tony Lindgren @ 2018-05-15  0:54 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <CAPDyKFqY5u3=db7-Xd9JXWo228PSNbH7-m-QNfSY9z8Z3p8t8A@mail.gmail.com>

* Ulf Hansson <ulf.hansson@linaro.org> [180514 18:59]:
> On 14 May 2018 at 17:19, Tony Lindgren <tony@atomide.com> wrote:
> > Reverting for 8c123c14bbba ("driver core: Respect all error codes from
> > dev_pm_domain_attach()") fixes the issue for me.
> >
> > Sounds like something is missing, any ideas?
> 
> This should solve the problem:
> 
> https://patchwork.kernel.org/patch/10398597/

Thanks yeah that fixes it for me too.

Regards,

Tony

^ permalink raw reply

* [PATCH] PM / Domains: Don't return -EEXIST at attach when PM domain exists
From: Tony Lindgren @ 2018-05-15  0:53 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1526309557-7995-1-git-send-email-ulf.hansson@linaro.org>

* Ulf Hansson <ulf.hansson@linaro.org> [180514 14:55]:
> As dev_pm_domain_attach() isn't the only way to assign PM domain pointers
> to devices, clearly we must allow a device to have the pointer already
> being assigned. For this reason, return 0 instead of -EEXIST.
> 
> Cc: Sylwester Nawrocki <s.nawrocki@samsung.com>
> Cc: Marek Szyprowski <m.szyprowski@samsung.com>
> Reported-by: Krzysztof Kozlowski <krzk@kernel.org>
> Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
> Tested-by: Tested-by: Krzysztof Kozlowski <krzk@kernel.org>

Fixes the issue for me too:

Tested-by: Tony Lindgren <tony@atomide.com>

^ permalink raw reply

* [PATCH] media: dvb-frontends: add Socionext SC1501A ISDB-S/T demodulator driver
From: Katsuhiro Suzuki @ 2018-05-15  0:37 UTC (permalink / raw)
  To: linux-arm-kernel

This patch adds a frontend driver for the Socionext SC1501A series
and Socionext MN88443x ISDB-S/T demodulators.

Signed-off-by: Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>
---
 drivers/media/dvb-frontends/Kconfig   |  10 +
 drivers/media/dvb-frontends/Makefile  |   1 +
 drivers/media/dvb-frontends/sc1501a.c | 802 ++++++++++++++++++++++++++
 drivers/media/dvb-frontends/sc1501a.h |  27 +
 4 files changed, 840 insertions(+)
 create mode 100644 drivers/media/dvb-frontends/sc1501a.c
 create mode 100644 drivers/media/dvb-frontends/sc1501a.h

diff --git a/drivers/media/dvb-frontends/Kconfig b/drivers/media/dvb-frontends/Kconfig
index 55e36a4f5215..e9d2c94b290e 100644
--- a/drivers/media/dvb-frontends/Kconfig
+++ b/drivers/media/dvb-frontends/Kconfig
@@ -739,6 +739,16 @@ config DVB_TC90522
 	  Toshiba TC90522 2xISDB-S 8PSK + 2xISDB-T OFDM demodulator.
 	  Say Y when you want to support this frontend.
 
+config DVB_SC1501A
+	tristate "Socionext SC1501A"
+	depends on DVB_CORE && I2C
+	select REGMAP_I2C
+	default m if !MEDIA_SUBDRV_AUTOSELECT
+	help
+	  A driver for Socionext SC1501A, MN884433 and MN884434
+	  ISDB-S + ISDB-T demodulator.
+	  Say Y when you want to support this frontend.
+
 comment "Digital terrestrial only tuners/PLL"
 	depends on DVB_CORE
 
diff --git a/drivers/media/dvb-frontends/Makefile b/drivers/media/dvb-frontends/Makefile
index 67a783fd5ed0..e204502347ed 100644
--- a/drivers/media/dvb-frontends/Makefile
+++ b/drivers/media/dvb-frontends/Makefile
@@ -125,6 +125,7 @@ obj-$(CONFIG_DVB_AF9033) += af9033.o
 obj-$(CONFIG_DVB_AS102_FE) += as102_fe.o
 obj-$(CONFIG_DVB_GP8PSK_FE) += gp8psk-fe.o
 obj-$(CONFIG_DVB_TC90522) += tc90522.o
+obj-$(CONFIG_DVB_SC1501A) += sc1501a.o
 obj-$(CONFIG_DVB_HORUS3A) += horus3a.o
 obj-$(CONFIG_DVB_ASCOT2E) += ascot2e.o
 obj-$(CONFIG_DVB_HELENE) += helene.o
diff --git a/drivers/media/dvb-frontends/sc1501a.c b/drivers/media/dvb-frontends/sc1501a.c
new file mode 100644
index 000000000000..6460d7f95b35
--- /dev/null
+++ b/drivers/media/dvb-frontends/sc1501a.c
@@ -0,0 +1,802 @@
+// SPDX-License-Identifier: GPL-2.0
+//
+// Socionext SC1501A series demodulator driver for ISDB-S/ISDB-T.
+//
+// Copyright (c) 2018 Socionext Inc.
+
+#include <linux/bitfield.h>
+#include <linux/clk.h>
+#include <linux/delay.h>
+#include <linux/gpio/consumer.h>
+#include <linux/of_device.h>
+#include <linux/regmap.h>
+#include <media/dvb_math.h>
+
+#include "sc1501a.h"
+
+/* ISDB-S registers */
+#define ATSIDU_S                                    0x2f
+#define ATSIDL_S                                    0x30
+#define TSSET_S                                     0x31
+#define AGCREAD_S                                   0x5a
+#define CPMON1_S                                    0x5e
+#define   CPMON1_S_FSYNC                              BIT(5)
+#define   CPMON1_S_ERRMON                             BIT(4)
+#define   CPMON1_S_SIGOFF                             BIT(3)
+#define   CPMON1_S_W2LOCK                             BIT(2)
+#define   CPMON1_S_W1LOCK                             BIT(1)
+#define   CPMON1_S_DW1LOCK                            BIT(0)
+#define TRMON_S                                     0x60
+#define BERCNFLG_S                                  0x68
+#define   BERCNFLG_S_BERVRDY                          BIT(5)
+#define   BERCNFLG_S_BERVCHK                          BIT(4)
+#define   BERCNFLG_S_BERDRDY                          BIT(3)
+#define   BERCNFLG_S_BERDCHK                          BIT(2)
+#define CNRDXU_S                                    0x69
+#define CNRDXL_S                                    0x6a
+#define CNRDYU_S                                    0x6b
+#define CNRDYL_S                                    0x6c
+#define BERVRDU_S                                   0x71
+#define BERVRDL_S                                   0x72
+#define DOSET1_S                                    0x73
+
+/* Primary ISDB-T */
+#define PLLASET1                                    0x00
+#define PLLASET2                                    0x01
+#define PLLBSET1                                    0x02
+#define PLLBSET2                                    0x03
+#define PLLSET                                      0x04
+#define OUTCSET                                     0x08
+#define   OUTCSET_CHDRV_8MA                           0xff
+#define   OUTCSET_CHDRV_4MA                           0x00
+#define PLDWSET                                     0x09
+#define   PLDWSET_NORMAL                             0x00
+#define   PLDWSET_PULLDOWN                           0xff
+#define HIZSET1                                     0x0a
+#define HIZSET2                                     0x0b
+
+/* Secondary ISDB-T (for MN884434 only) */
+#define RCVSET                                      0x00
+#define TSSET1_M                                    0x01
+#define TSSET2_M                                    0x02
+#define TSSET3_M                                    0x03
+#define INTACSET                                    0x08
+#define HIZSET3                                     0x0b
+
+/* ISDB-T registers */
+#define TSSET1                                      0x05
+#define   TSSET1_TSASEL_MASK                          GENMASK(4, 3)
+#define   TSSET1_TSASEL_ISDBT                         (0x0 << 3)
+#define   TSSET1_TSASEL_ISDBS                         (0x1 << 3)
+#define   TSSET1_TSASEL_NONE                          (0x2 << 3)
+#define   TSSET1_TSBSEL_MASK                          GENMASK(2, 1)
+#define   TSSET1_TSBSEL_ISDBS                         (0x0 << 1)
+#define   TSSET1_TSBSEL_ISDBT                         (0x1 << 1)
+#define   TSSET1_TSBSEL_NONE                          (0x2 << 1)
+#define TSSET2                                      0x06
+#define TSSET3                                      0x07
+#define   TSSET3_INTASEL_MASK                         GENMASK(7, 6)
+#define   TSSET3_INTASEL_T                            (0x0 << 6)
+#define   TSSET3_INTASEL_S                            (0x1 << 6)
+#define   TSSET3_INTASEL_NONE                         (0x2 << 6)
+#define   TSSET3_INTBSEL_MASK                         GENMASK(5, 4)
+#define   TSSET3_INTBSEL_S                            (0x0 << 4)
+#define   TSSET3_INTBSEL_T                            (0x1 << 4)
+#define   TSSET3_INTBSEL_NONE                         (0x2 << 4)
+#define OUTSET2                                     0x0d
+#define PWDSET                                      0x0f
+#define   PWDSET_OFDMPD_MASK                          GENMASK(3, 2)
+#define   PWDSET_OFDMPD_DOWN                          BIT(3)
+#define   PWDSET_PSKPD_MASK                           GENMASK(1, 0)
+#define   PWDSET_PSKPD_DOWN                           BIT(1)
+#define CLKSET1_T                                   0x11
+#define MDSET_T                                     0x13
+#define   MDSET_T_MDAUTO_MASK                         GENMASK(7, 4)
+#define   MDSET_T_MDAUTO_AUTO                         (0xf << 4)
+#define   MDSET_T_MDAUTO_MANUAL                       (0x0 << 4)
+#define   MDSET_T_FFTS_MASK                           GENMASK(3, 2)
+#define   MDSET_T_FFTS_MODE1                          (0x0 << 2)
+#define   MDSET_T_FFTS_MODE2                          (0x1 << 2)
+#define   MDSET_T_FFTS_MODE3                          (0x2 << 2)
+#define   MDSET_T_GI_MASK                             GENMASK(1, 0)
+#define   MDSET_T_GI_1_32                             (0x0 << 0)
+#define   MDSET_T_GI_1_16                             (0x1 << 0)
+#define   MDSET_T_GI_1_8                              (0x2 << 0)
+#define   MDSET_T_GI_1_4                              (0x3 << 0)
+#define MDASET_T                                    0x14
+#define ADCSET1_T                                   0x20
+#define   ADCSET1_T_REFSEL_MASK                       GENMASK(1, 0)
+#define   ADCSET1_T_REFSEL_2V                         (0x3 << 0)
+#define   ADCSET1_T_REFSEL_1_5V                       (0x2 << 0)
+#define   ADCSET1_T_REFSEL_1V                         (0x1 << 0)
+#define NCOFREQU_T                                  0x24
+#define NCOFREQM_T                                  0x25
+#define NCOFREQL_T                                  0x26
+#define FADU_T                                      0x27
+#define FADM_T                                      0x28
+#define FADL_T                                      0x29
+#define AGCSET2_T                                   0x2c
+#define   AGCSET2_T_IFPOLINV_INC                      BIT(0)
+#define   AGCSET2_T_RFPOLINV_INC                      BIT(1)
+#define AGCV3_T                                     0x3e
+#define MDRD_T                                      0xa2
+#define   MDRD_T_SEGID_MASK                           GENMASK(5, 4)
+#define   MDRD_T_SEGID_13                             (0x0 << 4)
+#define   MDRD_T_SEGID_1                              (0x1 << 4)
+#define   MDRD_T_SEGID_3                              (0x2 << 4)
+#define   MDRD_T_FFTS_MASK                            GENMASK(3, 2)
+#define   MDRD_T_FFTS_MODE1                           (0x0 << 2)
+#define   MDRD_T_FFTS_MODE2                           (0x1 << 2)
+#define   MDRD_T_FFTS_MODE3                           (0x2 << 2)
+#define   MDRD_T_GI_MASK                              GENMASK(1, 0)
+#define   MDRD_T_GI_1_32                              (0x0 << 0)
+#define   MDRD_T_GI_1_16                              (0x1 << 0)
+#define   MDRD_T_GI_1_8                               (0x2 << 0)
+#define   MDRD_T_GI_1_4                               (0x3 << 0)
+#define SSEQRD_T                                    0xa3
+#define   SSEQRD_T_SSEQSTRD_MASK                      GENMASK(3, 0)
+#define   SSEQRD_T_SSEQSTRD_RESET                     (0x0 << 0)
+#define   SSEQRD_T_SSEQSTRD_TUNING                    (0x1 << 0)
+#define   SSEQRD_T_SSEQSTRD_AGC                       (0x2 << 0)
+#define   SSEQRD_T_SSEQSTRD_SEARCH                    (0x3 << 0)
+#define   SSEQRD_T_SSEQSTRD_CLOCK_SYNC                (0x4 << 0)
+#define   SSEQRD_T_SSEQSTRD_FREQ_SYNC                 (0x8 << 0)
+#define   SSEQRD_T_SSEQSTRD_FRAME_SYNC                (0x9 << 0)
+#define   SSEQRD_T_SSEQSTRD_SYNC                      (0xa << 0)
+#define   SSEQRD_T_SSEQSTRD_LOCK                      (0xb << 0)
+#define AGCRDU_T                                    0xa8
+#define AGCRDL_T                                    0xa9
+#define CNRDU_T                                     0xbe
+#define CNRDL_T                                     0xbf
+#define BERFLG_T                                    0xc0
+#define   BERFLG_T_BERDRDY                            BIT(7)
+#define   BERFLG_T_BERDCHK                            BIT(6)
+#define   BERFLG_T_BERVRDYA                           BIT(5)
+#define   BERFLG_T_BERVCHKA                           BIT(4)
+#define   BERFLG_T_BERVRDYB                           BIT(3)
+#define   BERFLG_T_BERVCHKB                           BIT(2)
+#define   BERFLG_T_BERVRDYC                           BIT(1)
+#define   BERFLG_T_BERVCHKC                           BIT(0)
+#define BERRDU_T                                    0xc1
+#define BERRDM_T                                    0xc2
+#define BERRDL_T                                    0xc3
+#define BERLENRDU_T                                 0xc4
+#define BERLENRDL_T                                 0xc5
+#define ERRFLG_T                                    0xc6
+#define   ERRFLG_T_BERDOVF                            BIT(7)
+#define   ERRFLG_T_BERVOVFA                           BIT(6)
+#define   ERRFLG_T_BERVOVFB                           BIT(5)
+#define   ERRFLG_T_BERVOVFC                           BIT(4)
+#define   ERRFLG_T_NERRFA                             BIT(3)
+#define   ERRFLG_T_NERRFB                             BIT(2)
+#define   ERRFLG_T_NERRFC                             BIT(1)
+#define   ERRFLG_T_NERRF                              BIT(0)
+#define DOSET1_T                                    0xcf
+
+#define CLK_LOW            4000000
+#define CLK_DIRECT         20200000
+#define CLK_MAX            25410000
+
+#define S_T_FREQ           8126984 /* 512 / 63 MHz */
+
+struct sc1501a_spec {
+	bool primary;
+};
+
+struct sc1501a_priv {
+	const struct sc1501a_spec *spec;
+
+	struct dvb_frontend fe;
+	struct clk *mclk;
+	struct gpio_desc *reset_gpio;
+	u32 clk_freq;
+	u32 if_freq;
+
+	/* Common */
+	bool use_clkbuf;
+
+	/* ISDB-S */
+	struct i2c_client *client_s;
+	struct regmap *regmap_s;
+
+	/* ISDB-T */
+	struct i2c_client *client_t;
+	struct regmap *regmap_t;
+};
+
+static void sc1501a_cmn_power_on(struct sc1501a_priv *chip)
+{
+	struct regmap *r_t = chip->regmap_t;
+
+	clk_prepare_enable(chip->mclk);
+
+	gpiod_set_value_cansleep(chip->reset_gpio, 1);
+	usleep_range(100, 1000);
+	gpiod_set_value_cansleep(chip->reset_gpio, 0);
+
+	if (chip->spec->primary) {
+		regmap_write(r_t, OUTCSET, OUTCSET_CHDRV_8MA);
+		regmap_write(r_t, PLDWSET, PLDWSET_NORMAL);
+		regmap_write(r_t, HIZSET1, 0x80);
+		regmap_write(r_t, HIZSET2, 0xe0);
+	} else {
+		regmap_write(r_t, HIZSET3, 0x8f);
+	}
+}
+
+static void sc1501a_cmn_power_off(struct sc1501a_priv *chip)
+{
+	gpiod_set_value_cansleep(chip->reset_gpio, 1);
+
+	clk_disable_unprepare(chip->mclk);
+}
+
+static void sc1501a_s_sleep(struct sc1501a_priv *chip)
+{
+	struct regmap *r_t = chip->regmap_t;
+
+	regmap_update_bits(r_t, PWDSET, PWDSET_PSKPD_MASK,
+			   PWDSET_PSKPD_DOWN);
+}
+
+static void sc1501a_s_wake(struct sc1501a_priv *chip)
+{
+	struct regmap *r_t = chip->regmap_t;
+
+	regmap_update_bits(r_t, PWDSET, PWDSET_PSKPD_MASK, 0);
+}
+
+static void sc1501a_s_tune(struct sc1501a_priv *chip,
+			   struct dtv_frontend_properties *c)
+{
+	struct regmap *r_s = chip->regmap_s;
+
+	regmap_write(r_s, ATSIDU_S, c->stream_id >> 8);
+	regmap_write(r_s, ATSIDL_S, c->stream_id);
+	regmap_write(r_s, TSSET_S, 0);
+}
+
+static int sc1501a_s_read_status(struct sc1501a_priv *chip,
+				 struct dtv_frontend_properties *c,
+				 enum fe_status *status)
+{
+	struct regmap *r_s = chip->regmap_s;
+	u32 cpmon, tmpu, tmpl, flg;
+	u64 tmp;
+
+	/* Sync detection */
+	regmap_read(r_s, CPMON1_S, &cpmon);
+
+	*status = 0;
+	if (cpmon & CPMON1_S_FSYNC)
+		*status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	if (cpmon & CPMON1_S_W2LOCK)
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+	/* Signal strength */
+	c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+	if (*status & FE_HAS_SIGNAL) {
+		u32 agc;
+
+		regmap_read(r_s, AGCREAD_S, &tmpu);
+		agc = tmpu << 8;
+
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+		c->strength.stat[0].uvalue = agc;
+	}
+
+	/* C/N rate */
+	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+	if (*status & FE_HAS_VITERBI) {
+		u32 cnr = 0, x, y, d;
+		u64 d_3 = 0;
+
+		regmap_read(r_s, CNRDXU_S, &tmpu);
+		regmap_read(r_s, CNRDXL_S, &tmpl);
+		x = (tmpu << 8) | tmpl;
+		regmap_read(r_s, CNRDYU_S, &tmpu);
+		regmap_read(r_s, CNRDYL_S, &tmpl);
+		y = (tmpu << 8) | tmpl;
+
+		/* CNR[dB]: 10 * log10(D) - 30.74 / D^3 - 3 */
+		/*   D = x^2 / (2^15 * y - x^2) */
+		d = (y << 15) - x * x;
+		if (d > 0) {
+			/* (2^4 * D)^3 = 2^12 * D^3 */
+			/* 3.074 * 2^(12 + 24) = 211243671486 */
+			d_3 = div_u64(16 * x * x, d);
+			d_3 = d_3 * d_3 * d_3;
+			if (d_3)
+				d_3 = div_u64(211243671486, d_3);
+		}
+
+		if (d_3) {
+			/* 0.3 * 2^24 = 5033164 */
+			tmp = (s64)2 * intlog10(x) - intlog10(abs(d)) - d_3
+				- 5033164;
+			cnr = div_u64(tmp * 10000, 1 << 24);
+		}
+
+		if (cnr) {
+			c->cnr.len = 1;
+			c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+			c->cnr.stat[0].uvalue = cnr;
+		}
+	}
+
+	/* BER */
+	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+	regmap_read(r_s, BERCNFLG_S, &flg);
+
+	if ((*status & FE_HAS_VITERBI) && (flg & BERCNFLG_S_BERVRDY)) {
+		u32 bit_err, bit_cnt;
+
+		regmap_read(r_s, BERVRDU_S, &tmpu);
+		regmap_read(r_s, BERVRDL_S, &tmpl);
+		bit_err = (tmpu << 8) | tmpl;
+		bit_cnt = (1 << 13) * 204;
+
+		if (bit_cnt) {
+			c->post_bit_error.len = 1;
+			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_error.stat[0].uvalue = bit_err;
+			c->post_bit_count.len = 1;
+			c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_count.stat[0].uvalue = bit_cnt;
+		}
+	}
+
+	return 0;
+}
+
+static void sc1501a_t_sleep(struct sc1501a_priv *chip)
+{
+	struct regmap *r_t = chip->regmap_t;
+
+	regmap_update_bits(r_t, PWDSET, PWDSET_OFDMPD_MASK,
+			   PWDSET_OFDMPD_DOWN);
+}
+
+static void sc1501a_t_wake(struct sc1501a_priv *chip)
+{
+	struct regmap *r_t = chip->regmap_t;
+
+	regmap_update_bits(r_t, PWDSET, PWDSET_OFDMPD_MASK, 0);
+}
+
+static bool sc1501a_t_is_valid_clk(u32 adckt, u32 if_freq)
+{
+	if (if_freq == DIRECT_IF_57MHZ) {
+		if (adckt >= CLK_DIRECT && adckt <= 21000000)
+			return true;
+		if (adckt >= 25300000 && adckt <= CLK_MAX)
+			return true;
+	} else if (if_freq == DIRECT_IF_44MHZ) {
+		if (adckt >= 25000000 && adckt <= CLK_MAX)
+			return true;
+	} else if (if_freq >= LOW_IF_4MHZ && if_freq < DIRECT_IF_44MHZ) {
+		if (adckt >= CLK_DIRECT && adckt <= CLK_MAX)
+			return true;
+	}
+
+	return false;
+}
+
+static int sc1501a_t_set_freq(struct sc1501a_priv *chip)
+{
+	struct device *dev = &chip->client_s->dev;
+	struct regmap *r_t = chip->regmap_t;
+	s64 adckt, nco, ad_t;
+	u32 m, v;
+
+	/* Clock buffer (but not supported) or XTAL */
+	if (chip->clk_freq >= CLK_LOW && chip->clk_freq < CLK_DIRECT) {
+		chip->use_clkbuf = true;
+		regmap_write(r_t, CLKSET1_T, 0x07);
+
+		adckt = 0;
+	} else {
+		chip->use_clkbuf = false;
+		regmap_write(r_t, CLKSET1_T, 0x00);
+
+		adckt = chip->clk_freq;
+	}
+	if (!sc1501a_t_is_valid_clk(adckt, chip->if_freq)) {
+		dev_err(dev, "Invalid clock, CLK:%d, ADCKT:%lld, IF:%d\n",
+			chip->clk_freq, adckt, chip->if_freq);
+		return -EINVAL;
+	}
+
+	/* Direct IF or Low IF */
+	if (chip->if_freq == DIRECT_IF_57MHZ ||
+	    chip->if_freq == DIRECT_IF_44MHZ)
+		nco = adckt * 2 - chip->if_freq;
+	else
+		nco = -((s64)chip->if_freq);
+	nco = (nco << 24) / adckt;
+	ad_t = (adckt << 22) / S_T_FREQ;
+
+	regmap_write(r_t, NCOFREQU_T, nco >> 16);
+	regmap_write(r_t, NCOFREQM_T, nco >> 8);
+	regmap_write(r_t, NCOFREQL_T, nco);
+	regmap_write(r_t, FADU_T, ad_t >> 16);
+	regmap_write(r_t, FADM_T, ad_t >> 8);
+	regmap_write(r_t, FADL_T, ad_t);
+
+	/* Level of IF */
+	m = ADCSET1_T_REFSEL_MASK;
+	v = ADCSET1_T_REFSEL_1_5V;
+	regmap_update_bits(r_t, ADCSET1_T, m, v);
+
+	/* Polarity of AGC */
+	v = AGCSET2_T_IFPOLINV_INC | AGCSET2_T_RFPOLINV_INC;
+	regmap_update_bits(r_t, AGCSET2_T, v, v);
+
+	/* Lower output level of AGC */
+	regmap_write(r_t, AGCV3_T, 0x00);
+
+	regmap_write(r_t, MDSET_T, 0xfa);
+
+	return 0;
+}
+
+static void sc1501a_t_tune(struct sc1501a_priv *chip,
+			   struct dtv_frontend_properties *c)
+{
+	struct regmap *r_t = chip->regmap_t;
+	u32 m, v;
+
+	m = MDSET_T_MDAUTO_MASK | MDSET_T_FFTS_MASK | MDSET_T_GI_MASK;
+	v = MDSET_T_MDAUTO_AUTO | MDSET_T_FFTS_MODE3 | MDSET_T_GI_1_8;
+	regmap_update_bits(r_t, MDSET_T, m, v);
+
+	regmap_write(r_t, MDASET_T, 0);
+}
+
+static int sc1501a_t_read_status(struct sc1501a_priv *chip,
+				 struct dtv_frontend_properties *c,
+				 enum fe_status *status)
+{
+	struct regmap *r_t = chip->regmap_t;
+	u32 seqrd, st, flg, tmpu, tmpm, tmpl;
+	u64 tmp;
+
+	/* Sync detection */
+	regmap_read(r_t, SSEQRD_T, &seqrd);
+	st = seqrd & SSEQRD_T_SSEQSTRD_MASK;
+
+	*status = 0;
+	if (st >= SSEQRD_T_SSEQSTRD_SYNC)
+		*status |= FE_HAS_VITERBI | FE_HAS_SYNC | FE_HAS_LOCK;
+	if (st >= SSEQRD_T_SSEQSTRD_FRAME_SYNC)
+		*status |= FE_HAS_SIGNAL | FE_HAS_CARRIER;
+
+	/* Signal strength */
+	c->strength.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+	if (*status & FE_HAS_SIGNAL) {
+		u32 agc;
+
+		regmap_read(r_t, AGCRDU_T, &tmpu);
+		regmap_read(r_t, AGCRDL_T, &tmpl);
+		agc = (tmpu << 8) | tmpl;
+
+		c->strength.len = 1;
+		c->strength.stat[0].scale = FE_SCALE_RELATIVE;
+		c->strength.stat[0].uvalue = agc;
+	}
+
+	/* C/N rate */
+	c->cnr.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+	if (*status & FE_HAS_VITERBI) {
+		u32 cnr;
+
+		regmap_read(r_t, CNRDU_T, &tmpu);
+		regmap_read(r_t, CNRDL_T, &tmpl);
+
+		if (tmpu || tmpl) {
+			/* CNR[dB]: 10 * (log10(65536 / value) + 0.2) */
+			/* intlog10(65536) = 80807124, 0.2 * 2^24 = 3355443 */
+			tmp = (u64)80807124 - intlog10((tmpu << 8) | tmpl)
+				+ 3355443;
+			cnr = div_u64(tmp * 10000, 1 << 24);
+		} else {
+			cnr = 0;
+		}
+
+		c->cnr.len = 1;
+		c->cnr.stat[0].scale = FE_SCALE_DECIBEL;
+		c->cnr.stat[0].uvalue = cnr;
+	}
+
+	/* BER */
+	c->post_bit_error.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+	c->post_bit_count.stat[0].scale = FE_SCALE_NOT_AVAILABLE;
+
+	regmap_read(r_t, BERFLG_T, &flg);
+
+	if ((*status & FE_HAS_VITERBI) && (flg & BERFLG_T_BERVRDYA)) {
+		u32 bit_err, bit_cnt;
+
+		regmap_read(r_t, BERRDU_T, &tmpu);
+		regmap_read(r_t, BERRDM_T, &tmpm);
+		regmap_read(r_t, BERRDL_T, &tmpl);
+		bit_err = (tmpu << 16) | (tmpm << 8) | tmpl;
+
+		regmap_read(r_t, BERLENRDU_T, &tmpu);
+		regmap_read(r_t, BERLENRDL_T, &tmpl);
+		bit_cnt = ((tmpu << 8) | tmpl) * 203 * 8;
+
+		if (bit_cnt) {
+			c->post_bit_error.len = 1;
+			c->post_bit_error.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_error.stat[0].uvalue = bit_err;
+			c->post_bit_count.len = 1;
+			c->post_bit_count.stat[0].scale = FE_SCALE_COUNTER;
+			c->post_bit_count.stat[0].uvalue = bit_cnt;
+		}
+	}
+
+	return 0;
+}
+
+static int sc1501a_sleep(struct dvb_frontend *fe)
+{
+	struct sc1501a_priv *chip = fe->demodulator_priv;
+
+	sc1501a_s_sleep(chip);
+	sc1501a_t_sleep(chip);
+
+	return 0;
+}
+
+static int sc1501a_set_frontend(struct dvb_frontend *fe)
+{
+	struct sc1501a_priv *chip = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+	struct regmap *r_s = chip->regmap_s;
+	struct regmap *r_t = chip->regmap_t;
+	u8 tssel = 0, intsel = 0;
+
+	if (c->delivery_system == SYS_ISDBS) {
+		sc1501a_s_wake(chip);
+		sc1501a_t_sleep(chip);
+
+		tssel = TSSET1_TSASEL_ISDBS;
+		intsel = TSSET3_INTASEL_S;
+	} else if (c->delivery_system == SYS_ISDBT) {
+		sc1501a_s_sleep(chip);
+		sc1501a_t_wake(chip);
+
+		sc1501a_t_set_freq(chip);
+
+		tssel = TSSET1_TSASEL_ISDBT;
+		intsel = TSSET3_INTASEL_T;
+	}
+
+	regmap_update_bits(r_t, TSSET1,
+			   TSSET1_TSASEL_MASK | TSSET1_TSBSEL_MASK,
+			   tssel | TSSET1_TSBSEL_NONE);
+	regmap_write(r_t, TSSET2, 0);
+	regmap_update_bits(r_t, TSSET3,
+			   TSSET3_INTASEL_MASK | TSSET3_INTBSEL_MASK,
+			   intsel | TSSET3_INTBSEL_NONE);
+
+	regmap_write(r_t, DOSET1_T, 0x95);
+	regmap_write(r_s, DOSET1_S, 0x80);
+
+	if (c->delivery_system == SYS_ISDBS)
+		sc1501a_s_tune(chip, c);
+	else if (c->delivery_system == SYS_ISDBT)
+		sc1501a_t_tune(chip, c);
+
+	if (fe->ops.tuner_ops.set_params) {
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 1);
+		fe->ops.tuner_ops.set_params(fe);
+		if (fe->ops.i2c_gate_ctrl)
+			fe->ops.i2c_gate_ctrl(fe, 0);
+	}
+
+	return 0;
+}
+
+static int sc1501a_get_tune_settings(struct dvb_frontend *fe,
+				     struct dvb_frontend_tune_settings *s)
+{
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	s->min_delay_ms = 850;
+
+	if (c->delivery_system == SYS_ISDBS) {
+		s->max_drift = 30000 * 2 + 1;
+		s->step_size = 30000;
+	} else if (c->delivery_system == SYS_ISDBT) {
+		s->max_drift = 142857 * 2 + 1;
+		s->step_size = 142857 * 2;
+	}
+
+	return 0;
+}
+
+static int sc1501a_read_status(struct dvb_frontend *fe, enum fe_status *status)
+{
+	struct sc1501a_priv *chip = fe->demodulator_priv;
+	struct dtv_frontend_properties *c = &fe->dtv_property_cache;
+
+	if (c->delivery_system == SYS_ISDBS)
+		return sc1501a_s_read_status(chip, c, status);
+
+	if (c->delivery_system == SYS_ISDBT)
+		return sc1501a_t_read_status(chip, c, status);
+
+	return -EINVAL;
+}
+
+static const struct dvb_frontend_ops sc1501a_ops = {
+	.delsys = { SYS_ISDBS, SYS_ISDBT },
+	.info = {
+		.name          = "Socionext SC1501",
+		.frequency_min = 90000000,
+		.frequency_max = 2100000000,
+		.caps = FE_CAN_INVERSION_AUTO | FE_CAN_FEC_AUTO |
+			FE_CAN_QAM_AUTO | FE_CAN_TRANSMISSION_MODE_AUTO |
+			FE_CAN_GUARD_INTERVAL_AUTO | FE_CAN_HIERARCHY_AUTO,
+	},
+
+	.sleep                   = sc1501a_sleep,
+	.set_frontend            = sc1501a_set_frontend,
+	.get_tune_settings       = sc1501a_get_tune_settings,
+	.read_status             = sc1501a_read_status,
+};
+
+static const struct regmap_config regmap_config = {
+	.reg_bits   = 8,
+	.val_bits   = 8,
+	.cache_type = REGCACHE_NONE,
+};
+
+static int sc1501a_probe(struct i2c_client *client,
+			 const struct i2c_device_id *id)
+{
+	struct sc1501a_config *conf = client->dev.platform_data;
+	struct sc1501a_priv *chip;
+	struct device *dev = &client->dev;
+	int ret;
+
+	chip = devm_kzalloc(dev, sizeof(*chip), GFP_KERNEL);
+	if (!chip)
+		return -ENOMEM;
+
+	if (dev->of_node)
+		chip->spec = of_device_get_match_data(dev);
+	else
+		chip->spec = (struct sc1501a_spec *)id->driver_data;
+	if (!chip->spec)
+		return -EINVAL;
+
+	chip->mclk = devm_clk_get(dev, "mclk");
+	if (IS_ERR(chip->mclk) && !conf) {
+		dev_err(dev, "Failed to request mclk: %ld\n",
+			PTR_ERR(chip->mclk));
+		return PTR_ERR(chip->mclk);
+	}
+
+	ret = of_property_read_u32(dev->of_node, "if-frequency",
+				   &chip->if_freq);
+	if (ret && !conf) {
+		dev_err(dev, "Failed to load IF frequency: %d.\n", ret);
+		return ret;
+	}
+
+	chip->reset_gpio = devm_gpiod_get_optional(dev, "reset",
+						   GPIOD_OUT_HIGH);
+	if (IS_ERR(chip->reset_gpio)) {
+		dev_err(dev, "Failed to request reset_gpio: %ld\n",
+			PTR_ERR(chip->reset_gpio));
+		return PTR_ERR(chip->reset_gpio);
+	}
+
+	if (conf) {
+		chip->mclk = conf->mclk;
+		chip->if_freq = conf->if_freq;
+		chip->reset_gpio = conf->reset_gpio;
+
+		*conf->fe = &chip->fe;
+	}
+
+	chip->client_s = client;
+	chip->regmap_s = devm_regmap_init_i2c(chip->client_s, &regmap_config);
+	if (IS_ERR(chip->regmap_s))
+		return PTR_ERR(chip->regmap_s);
+
+	/*
+	 * Chip has two I2C addresses for each satellite/terrestrial system.
+	 * ISDB-T uses address ISDB-S + 4, so we register a dummy client.
+	 */
+	chip->client_t = i2c_new_dummy(client->adapter, client->addr + 4);
+	if (!chip->client_t)
+		return -ENODEV;
+
+	chip->regmap_t = devm_regmap_init_i2c(chip->client_t, &regmap_config);
+	if (IS_ERR(chip->regmap_t)) {
+		ret = PTR_ERR(chip->regmap_t);
+		goto err_i2c_t;
+	}
+
+	chip->clk_freq = clk_get_rate(chip->mclk);
+
+	memcpy(&chip->fe.ops, &sc1501a_ops, sizeof(sc1501a_ops));
+	chip->fe.demodulator_priv = chip;
+	i2c_set_clientdata(client, chip);
+
+	sc1501a_cmn_power_on(chip);
+	sc1501a_s_sleep(chip);
+	sc1501a_t_sleep(chip);
+
+	return 0;
+
+err_i2c_t:
+	i2c_unregister_device(chip->client_t);
+
+	return ret;
+}
+
+static int sc1501a_remove(struct i2c_client *client)
+{
+	struct sc1501a_priv *chip = i2c_get_clientdata(client);
+
+	sc1501a_cmn_power_off(chip);
+
+	i2c_unregister_device(chip->client_t);
+
+	return 0;
+}
+
+static const struct sc1501a_spec sc1501a_spec_pri = {
+	.primary = true,
+};
+
+static const struct sc1501a_spec sc1501a_spec_sec = {
+	.primary = false,
+};
+
+static const struct of_device_id sc1501a_of_match[] = {
+	{ .compatible = "socionext,mn884433",   .data = &sc1501a_spec_pri, },
+	{ .compatible = "socionext,mn884434-0", .data = &sc1501a_spec_pri, },
+	{ .compatible = "socionext,mn884434-1", .data = &sc1501a_spec_sec, },
+	{ .compatible = "socionext,sc1501a",    .data = &sc1501a_spec_pri, },
+	{}
+};
+MODULE_DEVICE_TABLE(of, sc1501a_of_match);
+
+static const struct i2c_device_id sc1501a_i2c_id[] = {
+	{ "mn884433",   (kernel_ulong_t)&sc1501a_spec_pri },
+	{ "mn884434-0", (kernel_ulong_t)&sc1501a_spec_pri },
+	{ "mn884434-1", (kernel_ulong_t)&sc1501a_spec_sec },
+	{ "sc1501a",    (kernel_ulong_t)&sc1501a_spec_pri },
+	{}
+};
+MODULE_DEVICE_TABLE(i2c, sc1501a_i2c_id);
+
+static struct i2c_driver sc1501a_driver = {
+	.driver = {
+		.name = "sc1501a",
+		.of_match_table = of_match_ptr(sc1501a_of_match),
+	},
+	.probe    = sc1501a_probe,
+	.remove   = sc1501a_remove,
+	.id_table = sc1501a_i2c_id,
+};
+
+module_i2c_driver(sc1501a_driver);
+
+MODULE_AUTHOR("Katsuhiro Suzuki <suzuki.katsuhiro@socionext.com>");
+MODULE_DESCRIPTION("Socionext SC1501A series demodulator driver.");
+MODULE_LICENSE("GPL v2");
diff --git a/drivers/media/dvb-frontends/sc1501a.h b/drivers/media/dvb-frontends/sc1501a.h
new file mode 100644
index 000000000000..7e247d44e4ac
--- /dev/null
+++ b/drivers/media/dvb-frontends/sc1501a.h
@@ -0,0 +1,27 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+/*
+ * Socionext SC1501A series demodulator driver for ISDB-S/ISDB-T.
+ *
+ * Copyright (c) 2018 Socionext Inc.
+ */
+
+#ifndef SC1501A_H
+#define SC1501A_H
+
+#include <media/dvb_frontend.h>
+
+/* ISDB-T IF frequency */
+#define DIRECT_IF_57MHZ    57000000
+#define DIRECT_IF_44MHZ    44000000
+#define LOW_IF_4MHZ        4000000
+
+struct sc1501a_config {
+	struct clk *mclk;
+	u32 if_freq;
+	struct gpio_desc *reset_gpio;
+
+	/* Everything after that is returned by the driver. */
+	struct dvb_frontend **fe;
+};
+
+#endif /* SC1501A_H */
-- 
2.17.0

^ permalink raw reply related

* [Linux-c6x-dev] [PATCH 05/20] c6x: use generic dma_noncoherent_ops
From: Mark Salter @ 2018-05-15  0:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180511075945.16548-6-hch@lst.de>

On Fri, 2018-05-11 at 09:59 +0200, Christoph Hellwig wrote:
> Switch to the generic noncoherent direct mapping implementation.
> 
> Signed-off-by: Christoph Hellwig <hch@lst.de>
> ---
>  arch/c6x/Kconfig                   |   3 +
>  arch/c6x/include/asm/Kbuild        |   1 +
>  arch/c6x/include/asm/dma-mapping.h |  28 ------
>  arch/c6x/include/asm/setup.h       |   2 +
>  arch/c6x/kernel/Makefile           |   2 +-
>  arch/c6x/kernel/dma.c              | 138 -----------------------------
>  arch/c6x/mm/dma-coherent.c         |  40 ++++++++-
>  7 files changed, 44 insertions(+), 170 deletions(-)
>  delete mode 100644 arch/c6x/include/asm/dma-mapping.h
>  delete mode 100644 arch/c6x/kernel/dma.c
> 
> diff --git a/arch/c6x/Kconfig b/arch/c6x/Kconfig
> index 8c088b96e372..bf59855628ac 100644
> --- a/arch/c6x/Kconfig
> +++ b/arch/c6x/Kconfig
> @@ -6,7 +6,10 @@
>  
>  config C6X
>  	def_bool y
> +	select ARCH_HAS_SYNC_DMA_FOR_CPU
> +	select ARCH_HAS_SYNC_DMA_FOR_DEVICE
>  	select CLKDEV_LOOKUP
> +	select DMA_NONCOHERENT_OPS
>  	select GENERIC_ATOMIC64
>  	select GENERIC_IRQ_SHOW
>  	select HAVE_ARCH_TRACEHOOK
> diff --git a/arch/c6x/include/asm/Kbuild b/arch/c6x/include/asm/Kbuild
> index fd4c840de837..434600e47662 100644
> --- a/arch/c6x/include/asm/Kbuild
> +++ b/arch/c6x/include/asm/Kbuild
> @@ -5,6 +5,7 @@ generic-y += current.h
>  generic-y += device.h
>  generic-y += div64.h
>  generic-y += dma.h
> +generic-y += dma-mapping.h
>  generic-y += emergency-restart.h
>  generic-y += exec.h
>  generic-y += extable.h
> diff --git a/arch/c6x/include/asm/dma-mapping.h b/arch/c6x/include/asm/dma-mapping.h
> deleted file mode 100644
> index 05daf1038111..000000000000
> --- a/arch/c6x/include/asm/dma-mapping.h
> +++ /dev/null
> @@ -1,28 +0,0 @@
> -/*
> - *  Port on Texas Instruments TMS320C6x architecture
> - *
> - *  Copyright (C) 2004, 2009, 2010, 2011 Texas Instruments Incorporated
> - *  Author: Aurelien Jacquiot <aurelien.jacquiot@ti.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.
> - *
> - */
> -#ifndef _ASM_C6X_DMA_MAPPING_H
> -#define _ASM_C6X_DMA_MAPPING_H
> -
> -extern const struct dma_map_ops c6x_dma_ops;
> -
> -static inline const struct dma_map_ops *get_arch_dma_ops(struct bus_type *bus)
> -{
> -	return &c6x_dma_ops;
> -}
> -
> -extern void coherent_mem_init(u32 start, u32 size);
> -void *c6x_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
> -		gfp_t gfp, unsigned long attrs);
> -void c6x_dma_free(struct device *dev, size_t size, void *vaddr,
> -		dma_addr_t dma_handle, unsigned long attrs);
> -
> -#endif	/* _ASM_C6X_DMA_MAPPING_H */
> diff --git a/arch/c6x/include/asm/setup.h b/arch/c6x/include/asm/setup.h
> index 852afb209afb..350f34debb19 100644
> --- a/arch/c6x/include/asm/setup.h
> +++ b/arch/c6x/include/asm/setup.h
> @@ -28,5 +28,7 @@ extern unsigned char c6x_fuse_mac[6];
>  extern void machine_init(unsigned long dt_ptr);
>  extern void time_init(void);
>  
> +extern void coherent_mem_init(u32 start, u32 size);
> +
>  #endif /* !__ASSEMBLY__ */
>  #endif /* _ASM_C6X_SETUP_H */
> diff --git a/arch/c6x/kernel/Makefile b/arch/c6x/kernel/Makefile
> index 02f340d7b8fe..fbe74174de87 100644
> --- a/arch/c6x/kernel/Makefile
> +++ b/arch/c6x/kernel/Makefile
> @@ -8,6 +8,6 @@ extra-y := head.o vmlinux.lds
>  obj-y := process.o traps.o irq.o signal.o ptrace.o
>  obj-y += setup.o sys_c6x.o time.o devicetree.o
>  obj-y += switch_to.o entry.o vectors.o c6x_ksyms.o
> -obj-y += soc.o dma.o
> +obj-y += soc.o
>  
>  obj-$(CONFIG_MODULES)           += module.o
> diff --git a/arch/c6x/kernel/dma.c b/arch/c6x/kernel/dma.c
> deleted file mode 100644
> index 31e1a9ec3a9c..000000000000
> --- a/arch/c6x/kernel/dma.c
> +++ /dev/null
> @@ -1,138 +0,0 @@
> -/*
> - *  Copyright (C) 2011 Texas Instruments Incorporated
> - *  Author: Mark Salter <msalter@redhat.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.
> - */
> -#include <linux/module.h>
> -#include <linux/dma-mapping.h>
> -#include <linux/mm.h>
> -#include <linux/mm_types.h>
> -#include <linux/scatterlist.h>
> -
> -#include <asm/cacheflush.h>
> -
> -static void c6x_dma_sync(dma_addr_t handle, size_t size,
> -			 enum dma_data_direction dir)
> -{
> -	unsigned long paddr = handle;
> -
> -	BUG_ON(!valid_dma_direction(dir));
> -
> -	switch (dir) {
> -	case DMA_FROM_DEVICE:
> -		L2_cache_block_invalidate(paddr, paddr + size);
> -		break;
> -	case DMA_TO_DEVICE:
> -		L2_cache_block_writeback(paddr, paddr + size);
> -		break;
> -	case DMA_BIDIRECTIONAL:
> -		L2_cache_block_writeback_invalidate(paddr, paddr + size);
> -		break;
> -	default:
> -		break;
> -	}
> -}
> -
> -static dma_addr_t c6x_dma_map_page(struct device *dev, struct page *page,
> -		unsigned long offset, size_t size, enum dma_data_direction dir,
> -		unsigned long attrs)
> -{
> -	dma_addr_t handle = virt_to_phys(page_address(page) + offset);
> -
> -	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
> -		c6x_dma_sync(handle, size, dir);
> -
> -	return handle;
> -}
> -
> -static void c6x_dma_unmap_page(struct device *dev, dma_addr_t handle,
> -		size_t size, enum dma_data_direction dir, unsigned long attrs)
> -{
> -	if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
> -		c6x_dma_sync(handle, size, dir);
> -}
> -
> -static int c6x_dma_map_sg(struct device *dev, struct scatterlist *sglist,
> -		int nents, enum dma_data_direction dir, unsigned long attrs)
> -{
> -	struct scatterlist *sg;
> -	int i;
> -
> -	for_each_sg(sglist, sg, nents, i) {
> -		sg->dma_address = sg_phys(sg);
> -		if (!(attrs & DMA_ATTR_SKIP_CPU_SYNC))
> -			c6x_dma_sync(sg->dma_address, sg->length, dir);
> -	}
> -
> -	return nents;
> -}
> -
> -static void c6x_dma_unmap_sg(struct device *dev, struct scatterlist *sglist,
> -		  int nents, enum dma_data_direction dir, unsigned long attrs)
> -{
> -	struct scatterlist *sg;
> -	int i;
> -
> -	if (attrs & DMA_ATTR_SKIP_CPU_SYNC)
> -		return;
> -
> -	for_each_sg(sglist, sg, nents, i)
> -		c6x_dma_sync(sg_dma_address(sg), sg->length, dir);
> -}
> -
> -static void c6x_dma_sync_single_for_cpu(struct device *dev, dma_addr_t handle,
> -		size_t size, enum dma_data_direction dir)
> -{
> -	c6x_dma_sync(handle, size, dir);
> -
> -}
> -
> -static void c6x_dma_sync_single_for_device(struct device *dev,
> -		dma_addr_t handle, size_t size, enum dma_data_direction dir)
> -{
> -	c6x_dma_sync(handle, size, dir);
> -
> -}
> -
> -static void c6x_dma_sync_sg_for_cpu(struct device *dev,
> -		struct scatterlist *sglist, int nents,
> -		enum dma_data_direction dir)
> -{
> -	struct scatterlist *sg;
> -	int i;
> -
> -	for_each_sg(sglist, sg, nents, i)
> -		c6x_dma_sync_single_for_cpu(dev, sg_dma_address(sg),
> -					sg->length, dir);
> -
> -}
> -
> -static void c6x_dma_sync_sg_for_device(struct device *dev,
> -		struct scatterlist *sglist, int nents,
> -		enum dma_data_direction dir)
> -{
> -	struct scatterlist *sg;
> -	int i;
> -
> -	for_each_sg(sglist, sg, nents, i)
> -		c6x_dma_sync_single_for_device(dev, sg_dma_address(sg),
> -					   sg->length, dir);
> -
> -}
> -
> -const struct dma_map_ops c6x_dma_ops = {
> -	.alloc			= c6x_dma_alloc,
> -	.free			= c6x_dma_free,
> -	.map_page		= c6x_dma_map_page,
> -	.unmap_page		= c6x_dma_unmap_page,
> -	.map_sg			= c6x_dma_map_sg,
> -	.unmap_sg		= c6x_dma_unmap_sg,
> -	.sync_single_for_device	= c6x_dma_sync_single_for_device,
> -	.sync_single_for_cpu	= c6x_dma_sync_single_for_cpu,
> -	.sync_sg_for_device	= c6x_dma_sync_sg_for_device,
> -	.sync_sg_for_cpu	= c6x_dma_sync_sg_for_cpu,
> -};
> -EXPORT_SYMBOL(c6x_dma_ops);
> diff --git a/arch/c6x/mm/dma-coherent.c b/arch/c6x/mm/dma-coherent.c
> index 95e38ad27c69..d0a8e0c4b27e 100644
> --- a/arch/c6x/mm/dma-coherent.c
> +++ b/arch/c6x/mm/dma-coherent.c
> @@ -19,10 +19,12 @@
>  #include <linux/bitops.h>
>  #include <linux/module.h>
>  #include <linux/interrupt.h>
> -#include <linux/dma-mapping.h>
> +#include <linux/dma-noncoherent.h>
>  #include <linux/memblock.h>
>  
> +#include <asm/cacheflush.h>
>  #include <asm/page.h>
> +#include <asm/setup.h>
>  
>  /*
>   * DMA coherent memory management, can be redefined using the memdma=
> @@ -73,7 +75,7 @@ static void __free_dma_pages(u32 addr, int order)
>   * Allocate DMA coherent memory space and return both the kernel
>   * virtual and DMA address for that space.
>   */
> -void *c6x_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
> +void *arch_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
>  		gfp_t gfp, unsigned long attrs)
>  {
>  	u32 paddr;
> @@ -98,7 +100,7 @@ void *c6x_dma_alloc(struct device *dev, size_t size, dma_addr_t *handle,
>  /*
>   * Free DMA coherent memory as defined by the above mapping.
>   */
> -void c6x_dma_free(struct device *dev, size_t size, void *vaddr,
> +void arch_dma_free(struct device *dev, size_t size, void *vaddr,
>  		dma_addr_t dma_handle, unsigned long attrs)
>  {
>  	int order;
> @@ -139,3 +141,35 @@ void __init coherent_mem_init(phys_addr_t start, u32 size)
>  	dma_bitmap = phys_to_virt(bitmap_phys);
>  	memset(dma_bitmap, 0, dma_pages * PAGE_SIZE);
>  }
> +
> +static void c6x_dma_sync(struct device *dev, phys_addr_t paddr, size_t size,
> +		enum dma_data_direction dir)
> +{
> +	BUG_ON(!valid_dma_direction(dir));
> +
> +	switch (dir) {
> +	case DMA_FROM_DEVICE:
> +		L2_cache_block_invalidate(paddr, paddr + size);
> +		break;
> +	case DMA_TO_DEVICE:
> +		L2_cache_block_writeback(paddr, paddr + size);
> +		break;
> +	case DMA_BIDIRECTIONAL:
> +		L2_cache_block_writeback_invalidate(paddr, paddr + size);
> +		break;
> +	default:
> +		break;
> +	}
> +}
> +
> +void arch_sync_dma_for_device(struct device *dev, phys_addr_t paddr,
> +		size_t size, enum dma_data_direction dir)
> +{
> +	return c6x_dma_sync(dev, paddr, size, dir);
> +}
> +
> +void arch_sync_dma_for_cpu(struct device *dev, phys_addr_t paddr,
> +		size_t size, enum dma_data_direction dir)
> +{
> +	return c6x_dma_sync(dev, paddr, size, dir);
> +}
Acked-by: Mark Salter <msalter@redhat.com>

^ permalink raw reply

* linux-next: manual merge of the samsung-krzk tree with the dma-mapping tree
From: Stephen Rothwell @ 2018-05-14 23:09 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180510091634.7fb3aaf2@canb.auug.org.au>

Hi all,

On Thu, 10 May 2018 09:16:34 +1000 Stephen Rothwell <sfr@canb.auug.org.au> wrote:
>
> Today's linux-next merge of the samsung-krzk tree got a conflict in:
> 
>   arch/arm/mach-exynos/Kconfig
> 
> between commit:
> 
>   4965a68780c5 ("arch: define the ARCH_DMA_ADDR_T_64BIT config symbol in lib/Kconfig")
> 
> from the dma-mapping tree and commit:
> 
>   c5deb598089c ("ARM: exynos: Remove support for Exynos5440")
> 
> from the samsung-krzk tree.
> 
> I fixed it up (the latter removed the whole section modified by
> the former, so I just removed the section) and can carry the fix as
> necessary. This is now fixed as far as linux-next is concerned, but any
> non trivial conflicts should be mentioned to your upstream maintainer
> when your tree is submitted for merging.  You may also want to consider
> cooperating with the maintainer of the conflicting tree to minimise any
> particularly complex conflicts.

This is now a conflict between the arm-soc tree and the dma-mapping tree.

-- 
Cheers,
Stephen Rothwell
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 488 bytes
Desc: OpenPGP digital signature
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180515/e2b00e44/attachment.sig>

^ permalink raw reply

* [PATCH 1/7] i2c: i2c-gpio: move header to platform_data
From: Greg Ungerer @ 2018-05-14 23:03 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180514213719.o6ceftp2quem3s7f@ninjato>


Hi Wolfram,

On 15/05/18 07:37, Wolfram Sang wrote:
>>   arch/arm/mach-ks8695/board-acs5k.c               | 2 +-
>>   arch/arm/mach-sa1100/simpad.c                    | 2 +-
>>   arch/mips/alchemy/board-gpr.c                    | 2 +-
> 
> Those still need acks...
> 
>> diff --git a/arch/arm/mach-ks8695/board-acs5k.c b/arch/arm/mach-ks8695/board-acs5k.c
>> index 937eb1d47e7b..ef835d82cdb9 100644
>> --- a/arch/arm/mach-ks8695/board-acs5k.c
>> +++ b/arch/arm/mach-ks8695/board-acs5k.c
>> @@ -19,7 +19,7 @@
>>   #include <linux/gpio/machine.h>
>>   #include <linux/i2c.h>
>>   #include <linux/i2c-algo-bit.h>
>> -#include <linux/i2c-gpio.h>
>> +#include <linux/platform_data/i2c-gpio.h>
>>   #include <linux/platform_data/pca953x.h>
>>   
>>   #include <linux/mtd/mtd.h>
> 
> ...
> 
>> diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
>> index ace010479eb6..49a61e6f3c5f 100644
>> --- a/arch/arm/mach-sa1100/simpad.c
>> +++ b/arch/arm/mach-sa1100/simpad.c
>> @@ -37,7 +37,7 @@
>>   #include <linux/input.h>
>>   #include <linux/gpio_keys.h>
>>   #include <linux/leds.h>
>> -#include <linux/i2c-gpio.h>
>> +#include <linux/platform_data/i2c-gpio.h>
>>   
>>   #include "generic.h"
>>   
>> diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c
>> index 4e79dbd54a33..fa75d75b5ba9 100644
>> --- a/arch/mips/alchemy/board-gpr.c
>> +++ b/arch/mips/alchemy/board-gpr.c
>> @@ -29,7 +29,7 @@
>>   #include <linux/leds.h>
>>   #include <linux/gpio.h>
>>   #include <linux/i2c.h>
>> -#include <linux/i2c-gpio.h>
>> +#include <linux/platform_data/i2c-gpio.h>
>>   #include <linux/gpio/machine.h>
>>   #include <asm/bootinfo.h>
>>   #include <asm/idle.h>
> 
> ... and this was the shortened diff for those.
> 
> Greg, Russell, Ralf, James? Is it okay if I take this via my tree?

Yes, I have no problem with that for the ks8695 part.

Acked-by: Greg Ungerer <gerg@uclinux.org>

Thanks
Greg


> Thanks,
> 
>     Wolfram
> 

^ permalink raw reply

* [RFC PATCH 02/10] dt-bindings: devfreq: rk3399_dmc: Add rockchip,pmu phandle.
From: Chanwoo Choi @ 2018-05-14 22:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180514211610.26618-3-enric.balletbo@collabora.com>

Hi,

On 2018? 05? 15? 06:16, Enric Balletbo i Serra wrote:
> The Rockchip DMC (Dynamic Memory Interface) needs to access to the PMU
> general register files to know the DRAM type, so add a phandle to the
> syscon that manages these registers.
> 
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
> 
>  Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt | 2 ++
>  1 file changed, 2 insertions(+)
> 
> diff --git a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt
> index 0ec68141f85a..951789c0cdd6 100644
> --- a/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt
> +++ b/Documentation/devicetree/bindings/devfreq/rk3399_dmc.txt
> @@ -12,6 +12,8 @@ Required properties:
>  			 for details.
>  - center-supply:	 DMC supply node.
>  - status:		 Marks the node enabled/disabled.
> +- rockchip,pmu:		 Phandle to the syscon managing the "PMU general register
> +			 files".
>  
>  Optional properties:
>  - interrupts:		 The CPU interrupt number. The interrupt specifier
> 

Reviewed-by: Chanwoo Choi <cw00.choi@samsung.com>

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply

* [RFC PATCH 03/10] devfreq: rk3399_dmc: Pass ODT and auto power down parameters to TF-A.
From: Chanwoo Choi @ 2018-05-14 22:20 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180514211610.26618-4-enric.balletbo@collabora.com>

Hi,

On 2018? 05? 15? 06:16, Enric Balletbo i Serra wrote:
> Trusted Firmware-A (TF-A) for rk3399 implements a SiP call to get the
> on-die termination (ODT) and auto power down parameters from kernel,
> this patch adds the functionality to do this. Also, if DDR clock
> frequency is lower than the on-die termination (ODT) disable frequency
> this driver should disable the DDR ODT.

I have a question.
'disable frequency' is the same meaning of 'disable the DDR ODT'?

> 
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
> 
>  drivers/devfreq/rk3399_dmc.c        | 50 ++++++++++++++++++++++++++++-
>  include/soc/rockchip/rockchip_sip.h |  1 +
>  2 files changed, 50 insertions(+), 1 deletion(-)
> 
> diff --git a/drivers/devfreq/rk3399_dmc.c b/drivers/devfreq/rk3399_dmc.c
> index d5c03e5abe13..cc1bbca3fb15 100644
> --- a/drivers/devfreq/rk3399_dmc.c
> +++ b/drivers/devfreq/rk3399_dmc.c
> @@ -18,14 +18,17 @@
>  #include <linux/devfreq.h>
>  #include <linux/devfreq-event.h>
>  #include <linux/interrupt.h>
> +#include <linux/mfd/syscon.h>
>  #include <linux/module.h>
>  #include <linux/of.h>
>  #include <linux/platform_device.h>
>  #include <linux/pm_opp.h>
> +#include <linux/regmap.h>
>  #include <linux/regulator/consumer.h>
>  #include <linux/rwsem.h>
>  #include <linux/suspend.h>
>  
> +#include <soc/rockchip/rk3399_grf.h>
>  #include <soc/rockchip/rockchip_sip.h>
>  
>  struct dram_timing {
> @@ -69,8 +72,11 @@ struct rk3399_dmcfreq {
>  	struct mutex lock;
>  	struct dram_timing timing;
>  	struct regulator *vdd_center;
> +	struct regmap *regmap_pmu;
>  	unsigned long rate, target_rate;
>  	unsigned long volt, target_volt;
> +	unsigned int odt_dis_freq;
> +	int odt_pd_arg0, odt_pd_arg1;
>  };
>  
>  static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
> @@ -80,6 +86,8 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
>  	struct dev_pm_opp *opp;
>  	unsigned long old_clk_rate = dmcfreq->rate;
>  	unsigned long target_volt, target_rate;
> +	struct arm_smccc_res res;
> +	int dram_flag;
>  	int err;
>  
>  	opp = devfreq_recommended_opp(dev, freq, flags);
> @@ -95,6 +103,15 @@ static int rk3399_dmcfreq_target(struct device *dev, unsigned long *freq,
>  
>  	mutex_lock(&dmcfreq->lock);
>  
> +	dram_flag = 0;

Also, if dram_flag is 0, it mean that disable ODT frequency?
If it's right, you better to define the precise variables as following
instead of just integer(0 or 1).
For example,
- ROCKCHIP_SIP_DRAM_FREQ_ENABLE
- ROCKCHIP_SIP_DRAM_FREQ_DISABLE

> +	if (target_rate >= dmcfreq->odt_dis_freq)
> +		dram_flag = 1;
> +
> +	arm_smccc_smc(ROCKCHIP_SIP_DRAM_FREQ, dmcfreq->odt_pd_arg0,
> +		      dmcfreq->odt_pd_arg1,
> +		      ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD,
> +		      dram_flag, 0, 0, 0, &res);
> +

This operation is special for only rk3399_dmc. It is difficult
to understand what to do. I recommend you better to add the detailed comment
with code.

>  	/*
>  	 * If frequency scaling from low to high, adjust voltage first.
>  	 * If frequency scaling from high to low, adjust frequency first.
> @@ -294,11 +311,13 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
>  {
>  	struct arm_smccc_res res;
>  	struct device *dev = &pdev->dev;
> -	struct device_node *np = pdev->dev.of_node;
> +	struct device_node *np = pdev->dev.of_node, *node;
>  	struct rk3399_dmcfreq *data;
>  	int ret, index, size;
>  	uint32_t *timing;
>  	struct dev_pm_opp *opp;
> +	u32 ddr_type;
> +	u32 val;
>  
>  	data = devm_kzalloc(dev, sizeof(struct rk3399_dmcfreq), GFP_KERNEL);
>  	if (!data)
> @@ -334,6 +353,29 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
>  		return ret;
>  	}
>  
> +	/* Try to find the optional reference to the pmu syscon */
> +	node = of_parse_phandle(np, "rockchip,pmu", 0);
> +	if (node) {
> +		data->regmap_pmu = syscon_node_to_regmap(node);
> +		if (IS_ERR(data->regmap_pmu))
> +			return PTR_ERR(data->regmap_pmu);
> +	}
> +
> +	/* Get DDR type */
> +	regmap_read(data->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
> +	ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) &
> +		    RK3399_PMUGRF_DDRTYPE_MASK;
> +
> +	/* Get the odt_dis_freq parameter in function of the DDR type */
> +	if (ddr_type == RK3399_PMUGRF_DDRTYPE_DDR3)
> +		data->odt_dis_freq = data->timing.ddr3_odt_dis_freq;
> +	else if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR3)
> +		data->odt_dis_freq = data->timing.lpddr3_odt_dis_freq;
> +	else if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR4)
> +		data->odt_dis_freq = data->timing.lpddr4_odt_dis_freq;
> +	else
> +		return -EINVAL;
> +

how about using 'switch' statement?

>  	/*
>  	 * Get dram timing and pass it to arm trust firmware,
>  	 * the dram drvier in arm trust firmware will get these
> @@ -358,6 +400,12 @@ static int rk3399_dmcfreq_probe(struct platform_device *pdev)
>  		      ROCKCHIP_SIP_CONFIG_DRAM_INIT,
>  		      0, 0, 0, 0, &res);
>  
> +	data->odt_pd_arg0 = (data->timing.sr_idle & 0xff) |
> +			    ((data->timing.sr_mc_gate_idle & 0xff) << 8) |
> +			    ((data->timing.standby_idle & 0xffff) << 16);
> +	data->odt_pd_arg1 = (data->timing.pd_idle & 0xfff) |
> +			    ((data->timing.srpd_lite_idle & 0xfff) << 16);
> +

odt_pd_arg0 and odt_pd_arg1 might be used for disabling/enabling the ODT frequency.
As I commented, it depend on only rk3399_dmc. You better to add detailed comment.

And I prefer to define the XXX_SHIFT/XXX_MASK definition instead of
using 8/16/0xff/0xffff for the readability.

>  	/*
>  	 * We add a devfreq driver to our parent since it has a device tree node
>  	 * with operating points.
> diff --git a/include/soc/rockchip/rockchip_sip.h b/include/soc/rockchip/rockchip_sip.h
> index 7e28092c4d3d..ad9482c56797 100644
> --- a/include/soc/rockchip/rockchip_sip.h
> +++ b/include/soc/rockchip/rockchip_sip.h
> @@ -23,5 +23,6 @@
>  #define ROCKCHIP_SIP_CONFIG_DRAM_GET_RATE	0x05
>  #define ROCKCHIP_SIP_CONFIG_DRAM_CLR_IRQ	0x06
>  #define ROCKCHIP_SIP_CONFIG_DRAM_SET_PARAM	0x07
> +#define ROCKCHIP_SIP_CONFIG_DRAM_SET_ODT_PD	0x08
>  
>  #endif
> 


-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply

* [PATCH v2] arm64: dts: qcom: Collapse usb support into one node
From: Stephen Boyd @ 2018-05-14 22:10 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <1523973390-2387-1-git-send-email-yossim@codeaurora.org>

Quoting Yossi Mansharoff (2018-04-17 06:56:30)
> We currently have three device nodes for the same USB hardware
> block, as evident by the reuse of the same reg address multiple
> times. Now that the chipidea driver fully supports OTG with the
> MSM wrapper we can collapse all these nodes into one USB device
> node, reflecting the true nature of the hardware.

None of this makes sense. Commit text is totally bogus now.

> 
> diff --git a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
> index 9ff8487..1505921 100644
> --- a/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
> +++ b/arch/arm64/boot/dts/qcom/apq8016-sbc.dtsi
> @@ -371,18 +372,18 @@
>                         adp-disable;
>                         hnp-disable;
>                         srp-disable;
> -                       dr_mode = "host";
> -                       pinctrl-names = "default";
> -                       pinctrl-0 = <&usb_sw_sel_pm>;
> +                       mux-controls = <&usb_switch>;
> +                       mux-control-names = "usb_switch";
> +
>                         ulpi {
>                                 phy {
>                                         v1p8-supply = <&pm8916_l7>;
>                                         v3p3-supply = <&pm8916_l13>;
> -                                       extcon = <&usb_id>;
>                                 };
>                         };
>                 };
>  
> +

Why the newline?

>                 lpass at 7708000 {
>                         status = "okay";
>                 };
> @@ -512,11 +513,17 @@
>  
>         usb_id: usb-id {
>                 compatible = "linux,extcon-usb-gpio";
> -               vbus-gpio = <&msmgpio 121 GPIO_ACTIVE_HIGH>;
> +               id-gpio = <&msmgpio 121 GPIO_ACTIVE_HIGH>;

Hmm?

>                 pinctrl-names = "default";
>                 pinctrl-0 = <&usb_id_default>;
>         };
>  
> +       usb_switch: usb-switch {
> +               compatible = "gpio-mux";

Needs a better compatible string for the actual mux part. The gpio-mux
can come after that because it's generic, but it's good to record the
actual mux part too.

> +               mux-gpios = <&pm8916_gpios 4 GPIO_ACTIVE_HIGH>;
> +               #mux-control-cells = <0>;
> +       };

^ permalink raw reply

* [PATCH 2/2] ARM: dts: chromecast: use PWM for LEDs
From: Thomas Hebb @ 2018-05-14 21:58 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <da60a97a0c6f754faa1f996334b3568ddb2f5ed0.1526334654.git.tommyhebb@gmail.com>

Control the Chromecast's two LEDs using PWM instead of GPIO pins. This
allows for variable brightness.

Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
---
 .../boot/dts/berlin2cd-google-chromecast.dts  | 20 ++++++++++++++-----
 1 file changed, 15 insertions(+), 5 deletions(-)

diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
index 54221f55bfa2..fb71e5436420 100644
--- a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
+++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
@@ -66,18 +66,21 @@
 	};
 
 	leds {
-		compatible = "gpio-leds";
+		compatible = "pwm-leds";
+		pinctrl-0 = <&ledpwm_pmux>;
+		pinctrl-names = "default";
 
 		white {
 			label = "white";
-			gpios = <&portc 1 GPIO_ACTIVE_HIGH>;
-			default-state = "keep";
+			pwms = <&pwm 0 600000 0>;
+			max-brightness = <255>;
+			linux,default-trigger = "default-on";
 		};
 
 		red {
 			label = "red";
-			gpios = <&portc 2 GPIO_ACTIVE_HIGH>;
-			default-state = "keep";
+			pwms = <&pwm 1 600000 0>;
+			max-brightness = <255>;
 		};
 	};
 };
@@ -96,3 +99,10 @@
 &usb_phy1 { status = "okay"; };
 
 &usb1 { status = "okay"; };
+
+&soc_pinctrl {
+	ledpwm_pmux: ledpwm-pmux {
+		groups = "G0";
+		function = "pwm";
+	};
+};
-- 
2.17.0

^ permalink raw reply related

* [PATCH] ARM: dts: chromecast: override bad bootloader memory info
From: Thomas Hebb @ 2018-05-14 21:56 UTC (permalink / raw)
  To: linux-arm-kernel

On the Chromecast, the bootloader provides us with an ATAG_MEM of
start=0x01000000 and size=0x3eff8000. This is clearly incorrect, as the
range given encompasses nearly a GiB but the Chromecast only has 512MiB
of RAM! Additionally, this causes the kernel to be decompressed at
0x00008000, below the claimed beginning of RAM, and so the boot fails.

Since the existing ATAG parsing code runs before the kernel is even
decompressed and irrevocably patches the device tree, don't even try
to bypass it. Instead, use the "linux,usable-memory" property instead
of the "reg" property to define the real range. The ATAG code only
overwrites reg, but linux,usable-memory is checked first in the OF
driver, so the fact that reg gets changed makes no difference.

Signed-off-by: Thomas Hebb <tommyhebb@gmail.com>
---
 arch/arm/boot/dts/berlin2cd-google-chromecast.dts | 12 +++++++++++-
 1 file changed, 11 insertions(+), 1 deletion(-)

diff --git a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
index 20f31cdeaf38..54221f55bfa2 100644
--- a/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
+++ b/arch/arm/boot/dts/berlin2cd-google-chromecast.dts
@@ -52,7 +52,17 @@
 
 	memory at 0 {
 		device_type = "memory";
-		reg = <0x00000000 0x20000000>; /* 512 MB */
+
+		/*
+		 * We're using "linux,usable-memory" instead of "reg" here
+		 * because the (signed and encrypted) bootloader that shipped
+		 * with this device provides an incorrect memory range in
+		 * ATAG_MEM. Linux helpfully overrides the "reg" property with
+		 * data from the ATAG, so we can't specify the proper range
+		 * normally. Fortunately, this alternate property is checked
+		 * first by the OF driver, so we can (ab)use it instead.
+		 */
+		linux,usable-memory = <0x00000000 0x20000000>; /* 512 MB */
 	};
 
 	leds {
-- 
2.17.0

^ permalink raw reply related

* [PATCH 1/4] amba: Export amba_bustype
From: Kim Phillips @ 2018-05-14 21:49 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <19c4b830-9f50-d5ea-3e31-587477210ee1@arm.com>

On Wed, 9 May 2018 17:02:34 +0100
Robin Murphy <robin.murphy@arm.com> wrote:

> probe (and thus call coresight_register()) first. Oh well, I guess 
> poking amba_bustype really does remain the only reasonable answer.

Thanks all, I've added Robin's Reviewed-by, and submitted this patch to
RMK's patch tracking system, here:

http://www.armlinux.org.uk/developer/patches/viewpatch.php?id=8773/1

Cheers,

Kim

^ permalink raw reply

* [RFC PATCH 01/10] devfreq: rockchip-dfi: Move GRF definitions to a common place.
From: Chanwoo Choi @ 2018-05-14 21:44 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180514211610.26618-2-enric.balletbo@collabora.com>

Hi Enric,

On 2018? 05? 15? 06:16, Enric Balletbo i Serra wrote:
> Some rk3399 GRF (Generic Register Files) definitions can be used for
> different drivers. Move these definitions to a common include so we
> don't need to duplicate these definitions.
> 
> Signed-off-by: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> ---
> 
>  drivers/devfreq/event/rockchip-dfi.c | 23 +++++++----------------
>  include/soc/rockchip/rk3399_grf.h    | 21 +++++++++++++++++++++
>  2 files changed, 28 insertions(+), 16 deletions(-)
>  create mode 100644 include/soc/rockchip/rk3399_grf.h
> 
> diff --git a/drivers/devfreq/event/rockchip-dfi.c b/drivers/devfreq/event/rockchip-dfi.c
> index 22b113363ffc..2fbbcbeb644f 100644
> --- a/drivers/devfreq/event/rockchip-dfi.c
> +++ b/drivers/devfreq/event/rockchip-dfi.c
> @@ -26,6 +26,8 @@
>  #include <linux/list.h>
>  #include <linux/of.h>
>  
> +#include <soc/rockchip/rk3399_grf.h>
> +
>  #define RK3399_DMC_NUM_CH	2
>  
>  /* DDRMON_CTRL */
> @@ -43,18 +45,6 @@
>  #define DDRMON_CH1_COUNT_NUM		0x3c
>  #define DDRMON_CH1_DFI_ACCESS_NUM	0x40
>  
> -/* pmu grf */
> -#define PMUGRF_OS_REG2	0x308
> -#define DDRTYPE_SHIFT	13
> -#define DDRTYPE_MASK	7
> -
> -enum {
> -	DDR3 = 3,
> -	LPDDR3 = 6,
> -	LPDDR4 = 7,
> -	UNUSED = 0xFF
> -};
> -
>  struct dmc_usage {
>  	u32 access;
>  	u32 total;
> @@ -83,16 +73,17 @@ static void rockchip_dfi_start_hardware_counter(struct devfreq_event_dev *edev)
>  	u32 ddr_type;
>  
>  	/* get ddr type */
> -	regmap_read(info->regmap_pmu, PMUGRF_OS_REG2, &val);
> -	ddr_type = (val >> DDRTYPE_SHIFT) & DDRTYPE_MASK;
> +	regmap_read(info->regmap_pmu, RK3399_PMUGRF_OS_REG2, &val);
> +	ddr_type = (val >> RK3399_PMUGRF_DDRTYPE_SHIFT) &
> +		    RK3399_PMUGRF_DDRTYPE_MASK;
>  
>  	/* clear DDRMON_CTRL setting */
>  	writel_relaxed(CLR_DDRMON_CTRL, dfi_regs + DDRMON_CTRL);
>  
>  	/* set ddr type to dfi */
> -	if (ddr_type == LPDDR3)
> +	if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR3)
>  		writel_relaxed(LPDDR3_EN, dfi_regs + DDRMON_CTRL);
> -	else if (ddr_type == LPDDR4)
> +	else if (ddr_type == RK3399_PMUGRF_DDRTYPE_LPDDR4)
>  		writel_relaxed(LPDDR4_EN, dfi_regs + DDRMON_CTRL);
>  
>  	/* enable count, use software mode */
> diff --git a/include/soc/rockchip/rk3399_grf.h b/include/soc/rockchip/rk3399_grf.h
> new file mode 100644
> index 000000000000..0f94034e2e9a
> --- /dev/null
> +++ b/include/soc/rockchip/rk3399_grf.h
> @@ -0,0 +1,21 @@
> +/* SPDX-License-Identifier: GPL-2.0+ */
> +/*
> + * Rockchip Generic Register Files definitions
> + *
> + * Copyright (c) 2018, Collabora Ltd.
> + * Author: Enric Balletbo i Serra <enric.balletbo@collabora.com>
> + */
> +
> +#ifndef __SOC_RK3399_GRF_H
> +#define __SOC_RK3399_GRF_H
> +
> +/* PMU GRF Registers */
> +#define RK3399_PMUGRF_OS_REG2		0x308
> +#define RK3399_PMUGRF_DDRTYPE_SHIFT	13
> +#define RK3399_PMUGRF_DDRTYPE_MASK	7
> +#define RK3399_PMUGRF_DDRTYPE_DDR3	3
> +#define RK3399_PMUGRF_DDRTYPE_LPDDR2	5
> +#define RK3399_PMUGRF_DDRTYPE_LPDDR3	6
> +#define RK3399_PMUGRF_DDRTYPE_LPDDR4	7
> +
> +#endif
> 

Looks good to me.
Acked-by: Chanwoo Choi <cw00.choi@samsung.com>

-- 
Best Regards,
Chanwoo Choi
Samsung Electronics

^ permalink raw reply

* [PATCH 1/7] i2c: i2c-gpio: move header to platform_data
From: James Hogan @ 2018-05-14 21:42 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180514213719.o6ceftp2quem3s7f@ninjato>

On Mon, May 14, 2018 at 11:37:20PM +0200, Wolfram Sang wrote:
> > diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c
> > index 4e79dbd54a33..fa75d75b5ba9 100644
> > --- a/arch/mips/alchemy/board-gpr.c
> > +++ b/arch/mips/alchemy/board-gpr.c
> > @@ -29,7 +29,7 @@
> >  #include <linux/leds.h>
> >  #include <linux/gpio.h>
> >  #include <linux/i2c.h>
> > -#include <linux/i2c-gpio.h>
> > +#include <linux/platform_data/i2c-gpio.h>
> >  #include <linux/gpio/machine.h>
> >  #include <asm/bootinfo.h>
> >  #include <asm/idle.h>

Acked-by: James Hogan <jhogan@kernel.org>

Cheers
James
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 228 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180514/3204a488/attachment.sig>

^ permalink raw reply

* [PATCH 1/7] i2c: i2c-gpio: move header to platform_data
From: Wolfram Sang @ 2018-05-14 21:37 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180419200015.15095-2-wsa@the-dreams.de>


>  arch/arm/mach-ks8695/board-acs5k.c               | 2 +-
>  arch/arm/mach-sa1100/simpad.c                    | 2 +-
>  arch/mips/alchemy/board-gpr.c                    | 2 +-

Those still need acks...

> diff --git a/arch/arm/mach-ks8695/board-acs5k.c b/arch/arm/mach-ks8695/board-acs5k.c
> index 937eb1d47e7b..ef835d82cdb9 100644
> --- a/arch/arm/mach-ks8695/board-acs5k.c
> +++ b/arch/arm/mach-ks8695/board-acs5k.c
> @@ -19,7 +19,7 @@
>  #include <linux/gpio/machine.h>
>  #include <linux/i2c.h>
>  #include <linux/i2c-algo-bit.h>
> -#include <linux/i2c-gpio.h>
> +#include <linux/platform_data/i2c-gpio.h>
>  #include <linux/platform_data/pca953x.h>
>  
>  #include <linux/mtd/mtd.h>

...

> diff --git a/arch/arm/mach-sa1100/simpad.c b/arch/arm/mach-sa1100/simpad.c
> index ace010479eb6..49a61e6f3c5f 100644
> --- a/arch/arm/mach-sa1100/simpad.c
> +++ b/arch/arm/mach-sa1100/simpad.c
> @@ -37,7 +37,7 @@
>  #include <linux/input.h>
>  #include <linux/gpio_keys.h>
>  #include <linux/leds.h>
> -#include <linux/i2c-gpio.h>
> +#include <linux/platform_data/i2c-gpio.h>
>  
>  #include "generic.h"
>  
> diff --git a/arch/mips/alchemy/board-gpr.c b/arch/mips/alchemy/board-gpr.c
> index 4e79dbd54a33..fa75d75b5ba9 100644
> --- a/arch/mips/alchemy/board-gpr.c
> +++ b/arch/mips/alchemy/board-gpr.c
> @@ -29,7 +29,7 @@
>  #include <linux/leds.h>
>  #include <linux/gpio.h>
>  #include <linux/i2c.h>
> -#include <linux/i2c-gpio.h>
> +#include <linux/platform_data/i2c-gpio.h>
>  #include <linux/gpio/machine.h>
>  #include <asm/bootinfo.h>
>  #include <asm/idle.h>

... and this was the shortened diff for those.

Greg, Russell, Ralf, James? Is it okay if I take this via my tree?

Thanks,

   Wolfram

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20180514/f3c37915/attachment.sig>

^ permalink raw reply

* [PATCH 12/12] of/platform: make the OF code aware of early platform drivers
From: Geert Uytterhoeven @ 2018-05-14 21:32 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180511162028.20616-13-brgl@bgdev.pl>

Hi Bartosz,

On Fri, May 11, 2018 at 6:20 PM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> Check the relevant flag in the device node and skip the allocation
> part for devices that were populated early.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Thanks for your patch!

> --- a/drivers/of/platform.c
> +++ b/drivers/of/platform.c

> @@ -196,9 +197,17 @@ static struct platform_device *of_platform_device_create_pdata(
>             of_node_test_and_set_flag(np, OF_POPULATED))
>                 return NULL;
>
> -       dev = of_device_alloc(np, bus_id, parent);
> -       if (!dev)
> -               goto err_clear_flag;
> +       if (of_node_check_flag(np, OF_POPULATED_EARLY)) {
> +               dev = of_early_to_platform_device(np);
> +               if (IS_ERR(dev))
> +                       goto err_clear_flag;
> +
> +               of_device_init(dev, np, bus_id, parent);
> +       } else {
> +               dev = of_device_alloc(np, bus_id, parent);
> +               if (!dev)
> +                       goto err_clear_flag;
> +       }

The above may become cleaner if:
  1. of_early_to_platform_device() would return NULL instead -ENOENT,
  2. of_device_alloc() would be split in alloc and init phases, too.

Then you can do:

        dev = of_node_check_flag(np, OF_POPULATED_EARLY)
                ? of_early_to_platform_device(np)
                 : __of_device_alloc(np, bus_id, parent);
        if (!dev)
                goto err_clear_flag;

        of_device_init(dev, np, bus_id, parent);

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH 09/12] platform/early: add an init section for early driver data
From: Geert Uytterhoeven @ 2018-05-14 21:29 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180511162028.20616-10-brgl@bgdev.pl>

Hi Bartosz,

On Fri, May 11, 2018 at 6:20 PM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> Provide a separate section in which pointers to early platform driver
> structs will be stored.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Thanks for your patch!

> --- a/include/asm-generic/vmlinux.lds.h
> +++ b/include/asm-generic/vmlinux.lds.h
> @@ -214,6 +214,16 @@
>  #define CPU_METHOD_OF_TABLES() OF_TABLE(CONFIG_SMP, cpu_method)
>  #define CPUIDLE_METHOD_OF_TABLES() OF_TABLE(CONFIG_CPU_IDLE, cpuidle_method)
>
> +#ifdef CONFIG_EARLY_PLATFORM
> +#define EARLY_PLATFORM_DRIVERS_TABLE()                                 \
> +       . = ALIGN(8);                                                   \

Should this use STRUCT_ALIGN() instead?

> +       VMLINUX_SYMBOL(__early_platform_drivers_table) = .;             \
> +       KEEP(*(__early_platform_drivers_table))                         \
> +       VMLINUX_SYMBOL(__early_platform_drivers_table_end) = .;
> +#else
> +#define EARLY_PLATFORM_DRIVERS_TABLE()
> +#endif

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH 08/12] of/platform: provide a separate routine for device initialization
From: Geert Uytterhoeven @ 2018-05-14 21:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180511162028.20616-9-brgl@bgdev.pl>

On Fri, May 11, 2018 at 6:20 PM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> The early platform device framework will need to initialize the
> platform device objects without them being allocated in
> of_device_alloc(). Provide a routine that allows it.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH 07/12] of/platform: provide a separate routine for setting up device resources
From: Geert Uytterhoeven @ 2018-05-14 21:26 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180511162028.20616-8-brgl@bgdev.pl>

On Fri, May 11, 2018 at 6:20 PM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> The early platform driver framework will need to setup the device
> resources before the regular populating of the device tree happens.
>
> Provide a separate function for that.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH 06/12] of: add a new flag for OF device nodes
From: Geert Uytterhoeven @ 2018-05-14 21:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180511162028.20616-7-brgl@bgdev.pl>

On Fri, May 11, 2018 at 6:20 PM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> This flag indicates that a device node has been populated early and
> that it needs different handling when called from
> of_platform_populate().
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH 05/12] platform: export platform_device_release() locally
From: Geert Uytterhoeven @ 2018-05-14 21:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180511162028.20616-6-brgl@bgdev.pl>

On Fri, May 11, 2018 at 6:20 PM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> The early platform driver mechanism will use this function as the
> device release callback. Make it available in drivers/base.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH 04/12] platform: provide a separate function for initializing platform devices
From: Geert Uytterhoeven @ 2018-05-14 21:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180511162028.20616-5-brgl@bgdev.pl>

On Fri, May 11, 2018 at 6:20 PM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> The early platform driver framework will allocate platform devices
> using its own internal mechanisms. Provide a function that allows to
> initialize a platform device object without allocating it.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply

* [PATCH 03/12] platform/early: export platform_match() locally
From: Geert Uytterhoeven @ 2018-05-14 21:25 UTC (permalink / raw)
  To: linux-arm-kernel
In-Reply-To: <20180511162028.20616-4-brgl@bgdev.pl>

On Fri, May 11, 2018 at 6:20 PM, Bartosz Golaszewski <brgl@bgdev.pl> wrote:
> From: Bartosz Golaszewski <bgolaszewski@baylibre.com>
>
> We will use this function to match devices in the early platform core
> code. Export it locally in drivers/base.
>
> Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com>

Reviewed-by: Geert Uytterhoeven <geert+renesas@glider.be>

Gr{oetje,eeting}s,

                        Geert

-- 
Geert Uytterhoeven -- There's lots of Linux beyond ia32 -- geert at linux-m68k.org

In personal conversations with technical people, I call myself a hacker. But
when I'm talking to journalists I just say "programmer" or something like that.
                                -- Linus Torvalds

^ permalink raw reply


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