* [RFC 3/4] KVM: arm/arm64: Refactor Stage2 PMD hugepages support
From: Punit Agrawal @ 2018-01-10 19:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110190729.18383-1-punit.agrawal@arm.com>
Refactor the stage2 PMD hugepages support to split out constructing the
PMD into a separate function. A similar pattern of code will be followed
when introducing PUD hugepages at stage 2 where we need to split support
between architecure specific and common code.
There is no functional change with this patch.
Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
---
virt/kvm/arm/mmu.c | 20 +++++++++++++++-----
1 file changed, 15 insertions(+), 5 deletions(-)
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index 02eefda5d71e..f02219a91b19 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -1282,6 +1282,17 @@ static void kvm_send_hwpoison_signal(unsigned long address,
send_sig_info(SIGBUS, &info, current);
}
+static pmd_t stage2_build_pmd(kvm_pfn_t pfn, pgprot_t mem_type, bool writable)
+{
+ pmd_t pmd = pfn_pmd(pfn, mem_type);
+
+ pmd = pmd_mkhuge(pmd);
+ if (writable)
+ pmd = kvm_s2pmd_mkwrite(pmd);
+
+ return pmd;
+}
+
static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
struct kvm_memory_slot *memslot, unsigned long hva,
unsigned long fault_status)
@@ -1386,12 +1397,11 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
hugetlb = transparent_hugepage_adjust(&pfn, &fault_ipa);
if (hugetlb) {
- pmd_t new_pmd = pfn_pmd(pfn, mem_type);
- new_pmd = pmd_mkhuge(new_pmd);
- if (writable) {
- new_pmd = kvm_s2pmd_mkwrite(new_pmd);
+ pmd_t new_pmd = stage2_build_pmd(pfn, mem_type, writable);
+
+ if (writable)
kvm_set_pfn_dirty(pfn);
- }
+
coherent_cache_guest_page(vcpu, pfn, PMD_SIZE);
ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
} else {
--
2.15.1
^ permalink raw reply related
* [RFC 4/4] KVM: arm64: Add support for PUD hugepages at stage 2
From: Punit Agrawal @ 2018-01-10 19:07 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110190729.18383-1-punit.agrawal@arm.com>
KVM only supports PMD hugepages at stage 2. Extend the stage 2 fault
handling to add support for PUD hugepages.
Addition of PUD hugpage support enables additional hugepage sizes (1G
with 4K granule and 4TB with 64k granule) which can be useful on cores
that have support for mapping larger block sizes in the TLB entries.
Signed-off-by: Punit Agrawal <punit.agrawal@arm.com>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Catalin Marinas <catalin.marinas@arm.com>
---
arch/arm/include/asm/kvm_mmu.h | 10 +++++
arch/arm/include/asm/pgtable-3level.h | 2 +
arch/arm64/include/asm/kvm_mmu.h | 19 +++++++++
arch/arm64/include/asm/pgtable-hwdef.h | 2 +
arch/arm64/include/asm/pgtable.h | 4 ++
virt/kvm/arm/mmu.c | 72 +++++++++++++++++++++++++++++-----
6 files changed, 99 insertions(+), 10 deletions(-)
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 3fbe919b9181..6e2e34348cb3 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -59,6 +59,10 @@ phys_addr_t kvm_get_idmap_vector(void);
int kvm_mmu_init(void);
void kvm_clear_hyp_idmap(void);
+static inline void kvm_set_pud(pud_t *pud, pud_t new_pud)
+{
+}
+
static inline void kvm_set_pmd(pmd_t *pmd, pmd_t new_pmd)
{
*pmd = new_pmd;
@@ -230,6 +234,12 @@ static inline unsigned int kvm_get_vmid_bits(void)
return 8;
}
+static inline pud_t stage2_build_pud(kvm_pfn_t pfn, pgprot_t mem_type,
+ bool writable)
+{
+ return __pud(0);
+}
+
#endif /* !__ASSEMBLY__ */
#endif /* __ARM_KVM_MMU_H__ */
diff --git a/arch/arm/include/asm/pgtable-3level.h b/arch/arm/include/asm/pgtable-3level.h
index 1a7a17b2a1ba..97e04fdbfa85 100644
--- a/arch/arm/include/asm/pgtable-3level.h
+++ b/arch/arm/include/asm/pgtable-3level.h
@@ -249,6 +249,8 @@ PMD_BIT_FUNC(mkyoung, |= PMD_SECT_AF);
#define pfn_pmd(pfn,prot) (__pmd(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot)
+#define pud_pfn(pud) (((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
+
/* represent a notpresent pmd by faulting entry, this is used by pmdp_invalidate */
static inline pmd_t pmd_mknotpresent(pmd_t pmd)
{
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index dbfd18e08cfb..89eac3dbe123 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -160,6 +160,7 @@ void kvm_clear_hyp_idmap(void);
#define kvm_set_pte(ptep, pte) set_pte(ptep, pte)
#define kvm_set_pmd(pmdp, pmd) set_pmd(pmdp, pmd)
+#define kvm_set_pud(pudp, pud) set_pud(pudp, pud)
static inline pte_t kvm_s2pte_mkwrite(pte_t pte)
{
@@ -173,6 +174,12 @@ static inline pmd_t kvm_s2pmd_mkwrite(pmd_t pmd)
return pmd;
}
+static inline pud_t kvm_s2pud_mkwrite(pud_t pud)
+{
+ pud_val(pud) |= PUD_S2_RDWR;
+ return pud;
+}
+
static inline void kvm_set_s2pte_readonly(pte_t *pte)
{
pteval_t old_pteval, pteval;
@@ -319,5 +326,17 @@ static inline unsigned int kvm_get_vmid_bits(void)
return (cpuid_feature_extract_unsigned_field(reg, ID_AA64MMFR1_VMIDBITS_SHIFT) == 2) ? 16 : 8;
}
+static inline pud_t stage2_build_pud(kvm_pfn_t pfn, pgprot_t mem_type,
+ bool writable)
+{
+ pud_t pud = pfn_pud(pfn, mem_type);
+
+ pud = pud_mkhuge(pud);
+ if (writable)
+ pud = kvm_s2pud_mkwrite(pud);
+
+ return pud;
+}
+
#endif /* __ASSEMBLY__ */
#endif /* __ARM64_KVM_MMU_H__ */
diff --git a/arch/arm64/include/asm/pgtable-hwdef.h b/arch/arm64/include/asm/pgtable-hwdef.h
index 40a998cdd399..a091a6192eee 100644
--- a/arch/arm64/include/asm/pgtable-hwdef.h
+++ b/arch/arm64/include/asm/pgtable-hwdef.h
@@ -181,6 +181,8 @@
#define PMD_S2_RDONLY (_AT(pmdval_t, 1) << 6) /* HAP[2:1] */
#define PMD_S2_RDWR (_AT(pmdval_t, 3) << 6) /* HAP[2:1] */
+#define PUD_S2_RDWR (_AT(pudval_t, 3) << 6) /* HAP[2:1] */
+
/*
* Memory Attribute override for Stage-2 (MemAttr[3:0])
*/
diff --git a/arch/arm64/include/asm/pgtable.h b/arch/arm64/include/asm/pgtable.h
index bdcc7f1c9d06..d5ffff4369d2 100644
--- a/arch/arm64/include/asm/pgtable.h
+++ b/arch/arm64/include/asm/pgtable.h
@@ -362,7 +362,11 @@ static inline int pmd_protnone(pmd_t pmd)
#define mk_pmd(page,prot) pfn_pmd(page_to_pfn(page),prot)
#define pud_write(pud) pte_write(pud_pte(pud))
+
+#define pud_mkhuge(pud) (__pud(pud_val(pud) & ~PUD_TABLE_BIT))
+
#define pud_pfn(pud) (((pud_val(pud) & PUD_MASK) & PHYS_MASK) >> PAGE_SHIFT)
+#define pfn_pud(pfn, prot) (__pud(((phys_addr_t)(pfn) << PAGE_SHIFT) | pgprot_val(prot)))
#define set_pmd_at(mm, addr, pmdp, pmd) set_pte_at(mm, addr, (pte_t *)pmdp, pmd_pte(pmd))
diff --git a/virt/kvm/arm/mmu.c b/virt/kvm/arm/mmu.c
index f02219a91b19..5362de098768 100644
--- a/virt/kvm/arm/mmu.c
+++ b/virt/kvm/arm/mmu.c
@@ -872,6 +872,32 @@ static pud_t *stage2_get_pud(struct kvm *kvm, struct kvm_mmu_memory_cache *cache
return stage2_pud_offset(pgd, addr);
}
+static int stage2_set_pud_huge(struct kvm *kvm, struct kvm_mmu_memory_cache
+ *cache, phys_addr_t addr, const pud_t *new_pud)
+{
+ pud_t *pud, old_pud;
+
+ pud = stage2_get_pud(kvm, cache, addr);
+ VM_BUG_ON(!pud);
+
+ /*
+ * Mapping in huge pages should only happen through a fault.
+ */
+ VM_BUG_ON(stage2_pud_present(*pud) &&
+ pud_pfn(*pud) != pud_pfn(*new_pud));
+
+ old_pud = *pud;
+ if (stage2_pud_present(old_pud)) {
+ stage2_pud_clear(pud);
+ kvm_tlb_flush_vmid_ipa(kvm, addr);
+ } else {
+ get_page(virt_to_page(pud));
+ }
+
+ kvm_set_pud(pud, *new_pud);
+ return 0;
+}
+
static pmd_t *stage2_get_pmd(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
phys_addr_t addr)
{
@@ -1307,6 +1333,7 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
kvm_pfn_t pfn;
pgprot_t mem_type = PAGE_S2;
bool logging_active = memslot_is_logging(memslot);
+ unsigned long vma_pagesize;
unsigned long flags = 0;
write_fault = kvm_is_write_fault(vcpu);
@@ -1324,9 +1351,13 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
return -EFAULT;
}
- if (vma_kernel_pagesize(vma) == PMD_SIZE && !logging_active) {
+ vma_pagesize = vma_kernel_pagesize(vma);
+ if ((vma_pagesize == PMD_SIZE || vma_pagesize == PUD_SIZE) &&
+ !logging_active) {
+ struct hstate *h = hstate_vma(vma);
+
hugetlb = true;
- gfn = (fault_ipa & PMD_MASK) >> PAGE_SHIFT;
+ gfn = (fault_ipa & huge_page_mask(h)) >> PAGE_SHIFT;
} else {
/*
* Pages belonging to memslots that don't have the same
@@ -1393,17 +1424,38 @@ static int user_mem_abort(struct kvm_vcpu *vcpu, phys_addr_t fault_ipa,
if (mmu_notifier_retry(kvm, mmu_seq))
goto out_unlock;
- if (!hugetlb && !force_pte)
+ if (!hugetlb && !force_pte) {
+ /*
+ * We only support PMD_SIZE transparent
+ * hugepages. This code will need updates if we enable
+ * other page sizes for THP.
+ */
hugetlb = transparent_hugepage_adjust(&pfn, &fault_ipa);
+ vma_pagesize = PMD_SIZE;
+ }
if (hugetlb) {
- pmd_t new_pmd = stage2_build_pmd(pfn, mem_type, writable);
-
- if (writable)
- kvm_set_pfn_dirty(pfn);
-
- coherent_cache_guest_page(vcpu, pfn, PMD_SIZE);
- ret = stage2_set_pmd_huge(kvm, memcache, fault_ipa, &new_pmd);
+ if (vma_pagesize == PUD_SIZE) {
+ pud_t new_pud;
+
+ new_pud = stage2_build_pud(pfn, mem_type, writable);
+ if (writable)
+ kvm_set_pfn_dirty(pfn);
+
+ coherent_cache_guest_page(vcpu, pfn, PUD_SIZE);
+ ret = stage2_set_pud_huge(kvm, memcache,
+ fault_ipa, &new_pud);
+ } else {
+ pmd_t new_pmd;
+
+ new_pmd = stage2_build_pmd(pfn, mem_type, writable);
+ if (writable)
+ kvm_set_pfn_dirty(pfn);
+
+ coherent_cache_guest_page(vcpu, pfn, PMD_SIZE);
+ ret = stage2_set_pmd_huge(kvm, memcache,
+ fault_ipa, &new_pmd);
+ }
} else {
pte_t new_pte = pfn_pte(pfn, mem_type);
--
2.15.1
^ permalink raw reply related
* [PATCH linux dev-4.10 0/6] Add support PECI and PECI hwmon drivers
From: Jae Hyun Yoo @ 2018-01-10 19:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110101755.GA5822@kroah.com>
On 1/10/2018 2:17 AM, Greg KH wrote:
> On Tue, Jan 09, 2018 at 02:31:20PM -0800, Jae Hyun Yoo wrote:
>> From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
>>
>> Hello,
>>
>> This patch set provides support for PECI of AST2400/2500 which can give us PECI
>> functionalities such as temperature monitoring, platform manageability,
>> processor diagnostics and failure analysis. Also provides generic peci.h and
>> peci_ioctl.h headers to provide compatibility to peci drivers that can be
>> implemented later e.g. Nuvoton's BMC SoC family.
>
> What is the "dev-4.10" in the subject for? 4.10 is really old and
> obsolete :(
>
> thanks,
>
> greg k-h
>
I made this patch set on top of the v4.10 which OpenBmc project is
currently using. I'll rebase this patch set onto the current kernel.org
mainline.
Thanks,
Jae
^ permalink raw reply
* [PATCH 1/6] Documentation: crypto: document crypto engine API
From: Corentin Labbe @ 2018-01-10 19:14 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <849600f6-3082-c090-205d-75e3d14b38f9@st.com>
On Wed, Jan 10, 2018 at 02:13:13PM +0000, Fabien DESSENNE wrote:
> Hi Corentin,
>
>
> Thank you for this new version which I have testes successfully with the
> stm32 hash & cryp drivers.
>
> As a general comment on this patchset, I would say that it does not
> cover all async requests: typically I need (for the pending stm32 cryp
> driver uprade) to use CryptoEngine to process AEAD requests which is not
> covered here.
>
> Could you please consider adding the 'transfer' and 'finalize' EXPORTed
> functions for aead requests? (the implementation is quite trivial)
>
> Have also a look at struct acomp_req (acompress.h) and struct
> kpp_request (kpp.h) which also use "struct crypto_async_request base"
>
>
> BR
>
> Fabien
>
Hello
Thanks for your review and test (could I add your tested-by ?).
I didn't add aead (and kpp/acompress), since I do not have any way to test it.
Since you have a way to test aead, I will add it to the next release.
Regards
>
> On 03/01/18 21:11, Corentin Labbe wrote:
> > Signed-off-by: Corentin Labbe <clabbe.montjoie@gmail.com>
> > ---
> > Documentation/crypto/crypto_engine.rst | 46 ++++++++++++++++++++++++++++++++++
> > 1 file changed, 46 insertions(+)
> > create mode 100644 Documentation/crypto/crypto_engine.rst
> >
> > diff --git a/Documentation/crypto/crypto_engine.rst b/Documentation/crypto/crypto_engine.rst
> > new file mode 100644
> > index 000000000000..b0ed37f9fb0c
> > --- /dev/null
> > +++ b/Documentation/crypto/crypto_engine.rst
> > @@ -0,0 +1,46 @@
> > +=============
> > +CRYPTO ENGINE
> > +=============
> > +
> > +Overview
> > +--------
> > +The crypto engine API (CE), is a crypto queue manager.
> > +
> > +Requirement
> > +-----------
> > +You have to put at start of your tfm_ctx the struct crypto_engine_reqctx
> > +struct your_tfm_ctx {
> > + struct crypto_engine_reqctx enginectx;
> > + ...
> > +};
> > +Why: Since CE manage only crypto_async_request, it cannot know the underlying
> > +request_type and so have access only on the TFM.
> > +So using container_of for accessing __ctx is impossible.
> > +Furthermore, the crypto engine cannot know the "struct your_tfm_ctx",
> > +so it must assume that crypto_engine_reqctx is at start of it.
> > +
> > +Order of operations
> > +-------------------
> > +You have to obtain a struct crypto_engine via crypto_engine_alloc_init().
> > +And start it via crypto_engine_start().
> > +
> > +Before transferring any request, you have to fill the enginectx.
> > +- prepare_request: (taking a function pointer) If you need to do some processing before doing the request
> > +- unprepare_request: (taking a function pointer) Undoing what's done in prepare_request
> > +- do_one_request: (taking a function pointer) Do encryption for current request
> > +
> > +Note: that those three functions get the crypto_async_request associated with the received request.
> > +So your need to get the original request via container_of(areq, struct yourrequesttype_request, base);
> > +
> > +When your driver receive a crypto_request, you have to transfer it to
> > +the cryptoengine via one of:
> > +- crypto_transfer_cipher_request_to_engine()
> > +- crypto_transfer_skcipher_request_to_engine()
> > +- crypto_transfer_akcipher_request_to_engine()
> > +- crypto_transfer_hash_request_to_engine()
> > +
> > +At the end of the request process, a call to one of the following function is needed:
> > +- crypto_finalize_cipher_request
> > +- crypto_finalize_skcipher_request
> > +- crypto_finalize_akcipher_request
> > +- crypto_finalize_hash_request
^ permalink raw reply
* [PATCH linux dev-4.10 0/6] Add support PECI and PECI hwmon drivers
From: Greg KH @ 2018-01-10 19:17 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <006c4a95-9299-bd17-6dec-52578e8461ae@linux.intel.com>
On Wed, Jan 10, 2018 at 11:14:34AM -0800, Jae Hyun Yoo wrote:
> On 1/10/2018 2:17 AM, Greg KH wrote:
> > On Tue, Jan 09, 2018 at 02:31:20PM -0800, Jae Hyun Yoo wrote:
> > > From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
> > >
> > > Hello,
> > >
> > > This patch set provides support for PECI of AST2400/2500 which can give us PECI
> > > functionalities such as temperature monitoring, platform manageability,
> > > processor diagnostics and failure analysis. Also provides generic peci.h and
> > > peci_ioctl.h headers to provide compatibility to peci drivers that can be
> > > implemented later e.g. Nuvoton's BMC SoC family.
> >
> > What is the "dev-4.10" in the subject for? 4.10 is really old and
> > obsolete :(
> >
> > thanks,
> >
> > greg k-h
> >
>
> I made this patch set on top of the v4.10 which OpenBmc project is currently
> using. I'll rebase this patch set onto the current kernel.org mainline.
What is "OpenBmc", and why are they using an obsolete and insecure
kernel for their project? That seems like a very foolish thing to do...
thanks,
greg k-h
^ permalink raw reply
* [PATCH v2 00/12] drm/sun4i: Add A83T HDMI support
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
This patch series implements support for A83T DW HDMI and PHY. Contrary to
v1 series, this one is based on latest linux-next, since all needed patches
were merged.
While exactly this combination of HDMI controller and PHY is not common in
Allwinner SoCs, this patch series nevertheless makes groundwork for other
SoCs, which have same DW HDMI IP block, but different PHYs, like H3 and H5.
Please take a look.
Best regards,
Jernej
Changes from v1:
- Collected ACKs
- Separated bindings for controller and PHY
- Split driver into two parts - controller and PHY
- HDMI PHY driver now uses regmap for writes
- added defines for PHY registers and bits
- updated DT entries to accomodate new bindings
- removed already merged clock patch
- reworked first clock patch according to comments
- added new clock patch which changes NKMP formula
- split TCON patch in two, one for quirk and one for new compatible
- reworked patch which exports DW HDMI PHY functions:
- remove "gen2" from some function names
- removed parameter from dw_hdmi_phy_reset()
- added address parameter to dw_hdmi_phy_i2c_set_addr()
- updated most of commit messages
Jernej Skrabec (12):
clk: sunxi-ng: Mask nkmp factors when setting register
clk: sunxi-ng: Change formula for NKMP PLLs
drm/bridge/synopsys: dw-hdmi: Enable workaround for v1.32a
drm/bridge/synopsys: dw-hdmi: Export some PHY related functions
drm/bridge/synopsys: dw-hdmi: Add deinit callback
dt-bindings: display: sun4i-drm: Add A83T HDMI pipeline
drm/sun4i: Add has_channel_0 TCON quirk
drm/sun4i: Add support for A83T second TCON
drm/sun4i: Add support for A83T second DE2 mixer
drm/sun4i: Implement A83T HDMI driver
ARM: dts: sun8i: a83t: Add HDMI display pipeline
ARM: dts: sun8i: a83t: Enable HDMI on BananaPi M3
.../bindings/display/sunxi/sun4i-drm.txt | 197 +++++++++++++-
arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts | 25 ++
arch/arm/boot/dts/sun8i-a83t.dtsi | 119 +++++++-
drivers/clk/sunxi-ng/ccu_nkmp.c | 27 +-
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 55 ++--
drivers/gpu/drm/sun4i/Kconfig | 9 +
drivers/gpu/drm/sun4i/Makefile | 4 +
drivers/gpu/drm/sun4i/sun4i_tcon.c | 46 +++-
drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 +
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 183 +++++++++++++
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 51 ++++
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 302 +++++++++++++++++++++
drivers/gpu/drm/sun4i/sun8i_mixer.c | 11 +
include/drm/bridge/dw_hdmi.h | 12 +
14 files changed, 993 insertions(+), 49 deletions(-)
create mode 100644 drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
create mode 100644 drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
create mode 100644 drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
--
2.15.1
^ permalink raw reply
* [PATCH v2 01/12] clk: sunxi-ng: Mask nkmp factors when setting register
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
Currently, if one of the factors isn't present, bit 0 gets always set to
1. For example, A83T has NMP PLLs modelled as NKMP PLL without K. Since
K is not specified, it's offset, width and shift is 0. Driver assumes
that lowest value possible is 1, otherwise we would get division by 0.
That situation causes that bit 0 is always set, which may change wanted
clock rate.
Fix that by masking every factor according to it's specified width.
Factors with width set to 0 won't have any influence to final register
value.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/clk/sunxi-ng/ccu_nkmp.c | 21 ++++++++++++---------
1 file changed, 12 insertions(+), 9 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
index e58c95787f94..a99068a08315 100644
--- a/drivers/clk/sunxi-ng/ccu_nkmp.c
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
@@ -134,6 +134,7 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
unsigned long parent_rate)
{
struct ccu_nkmp *nkmp = hw_to_ccu_nkmp(hw);
+ u32 n_mask, k_mask, m_mask, p_mask;
struct _ccu_nkmp _nkmp;
unsigned long flags;
u32 reg;
@@ -149,18 +150,20 @@ static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
ccu_nkmp_find_best(parent_rate, rate, &_nkmp);
+ n_mask = GENMASK(nkmp->n.width + nkmp->n.shift - 1, nkmp->n.shift);
+ k_mask = GENMASK(nkmp->k.width + nkmp->k.shift - 1, nkmp->k.shift);
+ m_mask = GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift);
+ p_mask = GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift);
+
spin_lock_irqsave(nkmp->common.lock, flags);
reg = readl(nkmp->common.base + nkmp->common.reg);
- reg &= ~GENMASK(nkmp->n.width + nkmp->n.shift - 1, nkmp->n.shift);
- reg &= ~GENMASK(nkmp->k.width + nkmp->k.shift - 1, nkmp->k.shift);
- reg &= ~GENMASK(nkmp->m.width + nkmp->m.shift - 1, nkmp->m.shift);
- reg &= ~GENMASK(nkmp->p.width + nkmp->p.shift - 1, nkmp->p.shift);
-
- reg |= (_nkmp.n - nkmp->n.offset) << nkmp->n.shift;
- reg |= (_nkmp.k - nkmp->k.offset) << nkmp->k.shift;
- reg |= (_nkmp.m - nkmp->m.offset) << nkmp->m.shift;
- reg |= ilog2(_nkmp.p) << nkmp->p.shift;
+ reg &= ~(n_mask | k_mask | m_mask | p_mask);
+
+ reg |= ((_nkmp.n - nkmp->n.offset) << nkmp->n.shift) & n_mask;
+ reg |= ((_nkmp.k - nkmp->k.offset) << nkmp->k.shift) & k_mask;
+ reg |= ((_nkmp.m - nkmp->m.offset) << nkmp->m.shift) & m_mask;
+ reg |= (ilog2(_nkmp.p) << nkmp->p.shift) & p_mask;
writel(reg, nkmp->common.base + nkmp->common.reg);
--
2.15.1
^ permalink raw reply related
* [PATCH v2 02/12] clk: sunxi-ng: Change formula for NKMP PLLs
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
This commit changes formula from this:
Freq = (parent_freq * N * K) / (M * P)
to this:
Freq = (parent_freq / M) * N * K / P
This improves situation when N is in the range 1-255. PLL parent clock
is almost always 24 MHz, which means that for N >= 180 original formula
overflows and result becomes useless. Situation can be improved if M is
used as predivider as it can be seen in the second formula. That way at
least M > 1 is considered, but it still leaves small gap for wrong result
when M = 1 and N >= 180.
Using M as predivider shouldn't cause any issue, because it is in range
1-4 at most, so there is no or only minimal rounding error.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/clk/sunxi-ng/ccu_nkmp.c | 6 +++---
1 file changed, 3 insertions(+), 3 deletions(-)
diff --git a/drivers/clk/sunxi-ng/ccu_nkmp.c b/drivers/clk/sunxi-ng/ccu_nkmp.c
index a99068a08315..e6c996ad4483 100644
--- a/drivers/clk/sunxi-ng/ccu_nkmp.c
+++ b/drivers/clk/sunxi-ng/ccu_nkmp.c
@@ -33,7 +33,7 @@ static void ccu_nkmp_find_best(unsigned long parent, unsigned long rate,
for (_p = nkmp->min_p; _p <= nkmp->max_p; _p <<= 1) {
unsigned long tmp_rate;
- tmp_rate = parent * _n * _k / (_m * _p);
+ tmp_rate = (parent / _m) * _n * _k / _p;
if (tmp_rate > rate)
continue;
@@ -107,7 +107,7 @@ static unsigned long ccu_nkmp_recalc_rate(struct clk_hw *hw,
p = reg >> nkmp->p.shift;
p &= (1 << nkmp->p.width) - 1;
- return (parent_rate * n * k >> p) / m;
+ return (parent_rate / m) * n * k >> p;
}
static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
@@ -127,7 +127,7 @@ static long ccu_nkmp_round_rate(struct clk_hw *hw, unsigned long rate,
ccu_nkmp_find_best(*parent_rate, rate, &_nkmp);
- return *parent_rate * _nkmp.n * _nkmp.k / (_nkmp.m * _nkmp.p);
+ return (*parent_rate / _nkmp.m) * _nkmp.n * _nkmp.k / _nkmp.p;
}
static int ccu_nkmp_set_rate(struct clk_hw *hw, unsigned long rate,
--
2.15.1
^ permalink raw reply related
* [PATCH v2 03/12] drm/bridge/synopsys: dw-hdmi: Enable workaround for v1.32a
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
Allwinner SoCs have dw hdmi controller v1.32a which exhibits same
magenta line issue as i.MX6Q and i.MX6DL. Enable workaround for it.
Tests show that one iteration is enough.
Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 8 +++++---
1 file changed, 5 insertions(+), 3 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index a38db40ce990..7ca14d7325b5 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1634,9 +1634,10 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
* then write one of the FC registers several times.
*
* The number of iterations matters and depends on the HDMI TX revision
- * (and possibly on the platform). So far only i.MX6Q (v1.30a) and
- * i.MX6DL (v1.31a) have been identified as needing the workaround, with
- * 4 and 1 iterations respectively.
+ * (and possibly on the platform). So far i.MX6Q (v1.30a), i.MX6DL
+ * (v1.31a) and multiple Allwinner SoCs (v1.32a) have been identified
+ * as needing the workaround, with 4 iterations for v1.30a and 1
+ * iteration for others.
*/
switch (hdmi->version) {
@@ -1644,6 +1645,7 @@ static void dw_hdmi_clear_overflow(struct dw_hdmi *hdmi)
count = 4;
break;
case 0x131a:
+ case 0x132a:
count = 1;
break;
default:
--
2.15.1
^ permalink raw reply related
* [PATCH v2 04/12] drm/bridge/synopsys: dw-hdmi: Export some PHY related functions
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
Parts of PHY code could be useful also for custom PHYs. For example,
Allwinner A83T has custom PHY which is probably Synopsys gen2 PHY
with few additional memory mapped registers, so most of the Synopsys PHY
related code could be reused.
Functions exported here are actually not specific to Synopsys PHYs but
to DWC HDMI controller PHY interface. This means that even if the PHY is
completely custom, i.e. not designed by Synopsys, exported functions can
be useful.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 44 +++++++++++++++++++++----------
include/drm/bridge/dw_hdmi.h | 11 ++++++++
2 files changed, 41 insertions(+), 14 deletions(-)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 7ca14d7325b5..7d80f4b56683 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -1037,19 +1037,21 @@ static void dw_hdmi_phy_enable_svsret(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SVSRET_MASK);
}
-static void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
+void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_PDDQ_OFFSET,
HDMI_PHY_CONF0_GEN2_PDDQ_MASK);
}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_pddq);
-static void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
+void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable)
{
hdmi_mask_writeb(hdmi, enable, HDMI_PHY_CONF0,
HDMI_PHY_CONF0_GEN2_TXPWRON_OFFSET,
HDMI_PHY_CONF0_GEN2_TXPWRON_MASK);
}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_gen2_txpwron);
static void dw_hdmi_phy_sel_data_en_pol(struct dw_hdmi *hdmi, u8 enable)
{
@@ -1065,6 +1067,22 @@ static void dw_hdmi_phy_sel_interface_control(struct dw_hdmi *hdmi, u8 enable)
HDMI_PHY_CONF0_SELDIPIF_MASK);
}
+void dw_hdmi_phy_reset(struct dw_hdmi *hdmi)
+{
+ /* PHY reset. The reset signal is active high on Gen2 PHYs. */
+ hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
+ hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_reset);
+
+void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address)
+{
+ hdmi_phy_test_clear(hdmi, 1);
+ hdmi_writeb(hdmi, address, HDMI_PHY_I2CM_SLAVE_ADDR);
+ hdmi_phy_test_clear(hdmi, 0);
+}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_i2c_set_addr);
+
static void dw_hdmi_phy_power_off(struct dw_hdmi *hdmi)
{
const struct dw_hdmi_phy_data *phy = hdmi->phy.data;
@@ -1203,16 +1221,11 @@ static int hdmi_phy_configure(struct dw_hdmi *hdmi)
if (phy->has_svsret)
dw_hdmi_phy_enable_svsret(hdmi, 1);
- /* PHY reset. The reset signal is active high on Gen2 PHYs. */
- hdmi_writeb(hdmi, HDMI_MC_PHYRSTZ_PHYRSTZ, HDMI_MC_PHYRSTZ);
- hdmi_writeb(hdmi, 0, HDMI_MC_PHYRSTZ);
+ dw_hdmi_phy_reset(hdmi);
hdmi_writeb(hdmi, HDMI_MC_HEACPHY_RST_ASSERT, HDMI_MC_HEACPHY_RST);
- hdmi_phy_test_clear(hdmi, 1);
- hdmi_writeb(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2,
- HDMI_PHY_I2CM_SLAVE_ADDR);
- hdmi_phy_test_clear(hdmi, 0);
+ dw_hdmi_phy_i2c_set_addr(hdmi, HDMI_PHY_I2CM_SLAVE_ADDR_PHY_GEN2);
/* Write to the PHY as configured by the platform */
if (pdata->configure_phy)
@@ -1251,15 +1264,16 @@ static void dw_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
dw_hdmi_phy_power_off(hdmi);
}
-static enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
- void *data)
+enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
+ void *data)
{
return hdmi_readb(hdmi, HDMI_PHY_STAT0) & HDMI_PHY_HPD ?
connector_status_connected : connector_status_disconnected;
}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_read_hpd);
-static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
- bool force, bool disabled, bool rxsense)
+void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
+ bool force, bool disabled, bool rxsense)
{
u8 old_mask = hdmi->phy_mask;
@@ -1271,8 +1285,9 @@ static void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
if (old_mask != hdmi->phy_mask)
hdmi_writeb(hdmi, hdmi->phy_mask, HDMI_PHY_MASK0);
}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_update_hpd);
-static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
+void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
{
/*
* Configure the PHY RX SENSE and HPD interrupts polarities and clear
@@ -1291,6 +1306,7 @@ static void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data)
hdmi_writeb(hdmi, ~(HDMI_IH_PHY_STAT0_HPD | HDMI_IH_PHY_STAT0_RX_SENSE),
HDMI_IH_MUTE_PHY_STAT0);
}
+EXPORT_SYMBOL_GPL(dw_hdmi_phy_setup_hpd);
static const struct dw_hdmi_phy_ops dw_hdmi_synopsys_phy_ops = {
.init = dw_hdmi_phy_init,
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 182f83283e24..4a35e5065f6f 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -157,7 +157,18 @@ void dw_hdmi_audio_enable(struct dw_hdmi *hdmi);
void dw_hdmi_audio_disable(struct dw_hdmi *hdmi);
/* PHY configuration */
+void dw_hdmi_phy_i2c_set_addr(struct dw_hdmi *hdmi, u8 address);
void dw_hdmi_phy_i2c_write(struct dw_hdmi *hdmi, unsigned short data,
unsigned char addr);
+enum drm_connector_status dw_hdmi_phy_read_hpd(struct dw_hdmi *hdmi,
+ void *data);
+void dw_hdmi_phy_update_hpd(struct dw_hdmi *hdmi, void *data,
+ bool force, bool disabled, bool rxsense);
+void dw_hdmi_phy_setup_hpd(struct dw_hdmi *hdmi, void *data);
+
+void dw_hdmi_phy_gen2_pddq(struct dw_hdmi *hdmi, u8 enable);
+void dw_hdmi_phy_gen2_txpwron(struct dw_hdmi *hdmi, u8 enable);
+void dw_hdmi_phy_reset(struct dw_hdmi *hdmi);
+
#endif /* __IMX_HDMI_H__ */
--
2.15.1
^ permalink raw reply related
* [PATCH v2 05/12] drm/bridge/synopsys: dw-hdmi: Add deinit callback
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
Some SoCs, like Allwinner A83T, have to do additional cleanup when
HDMI driver unloads. When using DW HDMI through DRM bridge API, there is
no place to store driver's private data so it can be accessed in unbind
function. Because of that, add deinit function which is called at the
very end, so drivers can do a proper cleanup.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/bridge/synopsys/dw-hdmi.c | 3 +++
include/drm/bridge/dw_hdmi.h | 1 +
2 files changed, 4 insertions(+)
diff --git a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
index 7d80f4b56683..1b7650f2b425 100644
--- a/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
+++ b/drivers/gpu/drm/bridge/synopsys/dw-hdmi.c
@@ -2589,6 +2589,9 @@ static void __dw_hdmi_remove(struct dw_hdmi *hdmi)
i2c_del_adapter(&hdmi->i2c->adap);
else
i2c_put_adapter(hdmi->ddc);
+
+ if (hdmi->plat_data->deinit)
+ hdmi->plat_data->deinit(hdmi->plat_data);
}
/* -----------------------------------------------------------------------------
diff --git a/include/drm/bridge/dw_hdmi.h b/include/drm/bridge/dw_hdmi.h
index 4a35e5065f6f..9ad83054a5dd 100644
--- a/include/drm/bridge/dw_hdmi.h
+++ b/include/drm/bridge/dw_hdmi.h
@@ -124,6 +124,7 @@ struct dw_hdmi_phy_ops {
struct dw_hdmi_plat_data {
struct regmap *regm;
+ void (*deinit)(const struct dw_hdmi_plat_data *pdata);
enum drm_mode_status (*mode_valid)(struct drm_connector *connector,
const struct drm_display_mode *mode);
unsigned long input_bus_format;
--
2.15.1
^ permalink raw reply related
* [PATCH v2 06/12] dt-bindings: display: sun4i-drm: Add A83T HDMI pipeline
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
This commit adds all necessary compatibles and descriptions needed to
implement A83T HDMI pipeline.
Mixer is already properly described, so only compatible is added.
However, A83T TV TCON, which is connected to HDMI, doesn't have channel 0,
contrary to all TCONs currently described. Because of that, TCON
documentation is extended.
A83T features Synopsys DW HDMI controller with a custom PHY which looks
like Synopsys Gen2 PHY with few additions. Since there is no
documentation, needed properties were found out through experimentation
and reading BSP code.
At the end, example is added for newer SoCs, which feature DE2 and DW
HDMI.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
.../bindings/display/sunxi/sun4i-drm.txt | 197 ++++++++++++++++++++-
1 file changed, 190 insertions(+), 7 deletions(-)
diff --git a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
index cd626ee1147a..4fb380f3e53d 100644
--- a/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
+++ b/Documentation/devicetree/bindings/display/sunxi/sun4i-drm.txt
@@ -64,6 +64,52 @@ Required properties:
first port should be the input endpoint. The second should be the
output, usually to an HDMI connector.
+DWC HDMI TX Encoder
+-------------------
+
+The HDMI transmitter is a Synopsys DesignWare HDMI 1.4 TX controller IP
+with Allwinner's own PHY IP. It supports audio and video outputs and CEC.
+
+These DT bindings follow the Synopsys DWC HDMI TX bindings defined in
+Documentation/devicetree/bindings/display/bridge/dw_hdmi.txt with the
+following device-specific properties.
+
+Required properties:
+
+ - compatible: value must be one of:
+ * "allwinner,sun8i-a83t-dw-hdmi"
+ - reg: base address and size of memory-mapped region
+ - reg-io-width: See dw_hdmi.txt. Shall be 1.
+ - interrupts: HDMI interrupt number
+ - clocks: phandles to the clocks feeding the HDMI encoder
+ * iahb: the HDMI bus clock
+ * isfr: the HDMI register clock
+ - clock-names: the clock names mentioned above
+ - resets: phandle to the reset controller
+ - reset-names: must be "ctrl"
+ - phys: phandle to the DWC HDMI PHY
+ - phy-names: must be "phy"
+
+ - ports: A ports node with endpoint definitions as defined in
+ Documentation/devicetree/bindings/media/video-interfaces.txt. The
+ first port should be the input endpoint. The second should be the
+ output, usually to an HDMI connector.
+
+DWC HDMI PHY
+------------
+
+Required properties:
+ - compatible: value must be one of:
+ * allwinner,sun8i-a83t-hdmi-phy
+ - reg: base address and size of memory-mapped region
+ - clocks: phandles to the clocks feeding the HDMI PHY
+ * bus: the HDMI PHY interface clock
+ * mod: the HDMI PHY module clock
+ * tmds: TMDS clock
+ - clock-names: the clock names mentioned above
+ - resets: phandle to the reset controller driving the PHY
+ - reset-names: must be "phy"
+
TV Encoder
----------
@@ -94,24 +140,23 @@ Required properties:
* allwinner,sun7i-a20-tcon
* allwinner,sun8i-a33-tcon
* allwinner,sun8i-a83t-tcon-lcd
+ * allwinner,sun8i-a83t-tcon-tv
* allwinner,sun8i-v3s-tcon
- reg: base address and size of memory-mapped region
- interrupts: interrupt associated to this IP
- - clocks: phandles to the clocks feeding the TCON. Three are needed:
+ - clocks: phandles to the clocks feeding the TCON. One is needed:
- 'ahb': the interface clocks
- - 'tcon-ch0': The clock driving the TCON channel 0
- resets: phandles to the reset controllers driving the encoder
- "lcd": the reset line for the TCON channel 0
- clock-names: the clock names mentioned above
- reset-names: the reset names mentioned above
- - clock-output-names: Name of the pixel clock created
- ports: A ports node with endpoint definitions as defined in
Documentation/devicetree/bindings/media/video-interfaces.txt. The
first port should be the input endpoint, the second one the output
- The output may have multiple endpoints. The TCON has two channels,
+ The output may have multiple endpoints. TCON can have two channels,
usually with the first channel being used for the panels interfaces
(RGB, LVDS, etc.), and the second being used for the outputs that
require another controller (TV Encoder, HDMI, etc.). The endpoints
@@ -119,11 +164,16 @@ Required properties:
channel the endpoint is associated to. If that property is not
present, the endpoint number will be used as the channel number.
+When TCON supports channel 0 (all TCONs except TV TCON on A83T), two
+more clocks are needed:
+ - 'tcon-ch0': The clock driving the TCON channel 0
+ - clock-output-names: Name of the pixel clock created
+
On SoCs other than the A33 and V3s, there is one more clock required:
- 'tcon-ch1': The clock driving the TCON channel 1
-On SoCs that support LVDS (all SoCs but the A13, H3, H5 and V3s), you
-need one more reset line:
+When TCON support LVDS (all TCONs except TV TCON on A83T and those found
+in A13, H3, H5 and V3s SoCs), you need one more reset line:
- 'lvds': The reset line driving the LVDS logic
And on the A23, A31, A31s and A33, you need one more clock line:
@@ -226,6 +276,7 @@ supported.
Required properties:
- compatible: value must be one of:
* allwinner,sun8i-a83t-de2-mixer-0
+ * allwinner,sun8i-a83t-de2-mixer-1
* allwinner,sun8i-v3s-de2-mixer
- reg: base address and size of the memory-mapped region.
- clocks: phandles to the clocks feeding the mixer
@@ -261,7 +312,7 @@ Required properties:
- allwinner,pipelines: list of phandle to the display engine
frontends (DE 1.0) or mixers (DE 2.0) available.
-Example:
+Example 1:
panel: panel {
compatible = "olimex,lcd-olinuxino-43-ts";
@@ -460,3 +511,135 @@ display-engine {
compatible = "allwinner,sun5i-a13-display-engine";
allwinner,pipelines = <&fe0>;
};
+
+Example 2:
+
+connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+};
+
+de: display-engine {
+ compatible = "allwinner,sun8i-a83t-display-engine";
+ allwinner,pipelines = <&mixer1>;
+};
+
+mixer1: mixer at 1200000 {
+ compatible = "allwinner,sun8i-a83t-de2-mixer-1";
+ reg = <0x01200000 0x100000>;
+ clocks = <&display_clocks CLK_BUS_MIXER1>,
+ <&display_clocks CLK_MIXER1>;
+ clock-names = "bus",
+ "mod";
+ resets = <&display_clocks RST_WB>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mixer1_out: port at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ mixer1_out_tcon1: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&tcon1_in_mixer1>;
+ };
+ };
+ };
+};
+
+tcon1: lcd-controller at 1c0d000 {
+ compatible = "allwinner,sun8i-a83t-tcon-tv";
+ reg = <0x01c0d000 0x1000>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_TCON1>, <&ccu CLK_TCON1>;
+ clock-names = "ahb", "tcon-ch1";
+ resets = <&ccu RST_BUS_TCON1>;
+ reset-names = "lcd";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tcon1_in: port at 0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ tcon1_in_mixer1: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&mixer1_out_tcon1>;
+ };
+ };
+
+ tcon1_out: port at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tcon1_out_hdmi: endpoint at 1 {
+ reg = <1>;
+ remote-endpoint = <&hdmi_in_tcon1>;
+ };
+ };
+ };
+};
+
+hdmi: hdmi at 1ee0000 {
+ compatible = "allwinner,sun8i-a83t-dw-hdmi";
+ reg = <0x01ee0000 0x10000>;
+ reg-io-width = <1>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_SLOW>;
+ clock-names = "iahb", "isfr";
+ resets = <&ccu RST_BUS_HDMI1>;
+ reset-names = "ctrl";
+ phys = <&hdmi_phy>;
+ phy-names = "hdmi-phy";
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hdmi_in: port at 0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ hdmi_in_tcon1: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&tcon1_out_hdmi>;
+ };
+ };
+
+ hdmi_out: port at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+ };
+ };
+};
+
+hdmi_phy: hdmi-phy at 1ef0000 {
+ compatible = "allwinner,sun8i-a83t-hdmi-phy";
+ reg = <0x01ef0000 0x10000>;
+ clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_SLOW>,
+ <&ccu CLK_HDMI>;
+ clock-names = "bus", "mod", "tmds";
+ resets = <&ccu RST_BUS_HDMI0>;
+ reset-names = "phy";
+ #phy-cells = <0>;
+};
--
2.15.1
^ permalink raw reply related
* [PATCH v2 07/12] drm/sun4i: Add has_channel_0 TCON quirk
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
Some TCONs on newer SoCs doesn't support channel 0, since they are meant
to be used only with TV or HDMI encoder.
Prepare support for them with adding has_channel_0 quirk.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 41 +++++++++++++++++++++++++++-----------
drivers/gpu/drm/sun4i/sun4i_tcon.h | 1 +
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index b78fed809992..0815c528d08e 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -84,6 +84,7 @@ static void sun4i_tcon_channel_set_status(struct sun4i_tcon *tcon, int channel,
switch (channel) {
case 0:
+ WARN_ON(!tcon->quirks->has_channel_0);
regmap_update_bits(tcon->regs, SUN4I_TCON0_CTL_REG,
SUN4I_TCON0_CTL_TCON_ENABLE,
enabled ? SUN4I_TCON0_CTL_TCON_ENABLE : 0);
@@ -276,6 +277,8 @@ static void sun4i_tcon0_mode_set_lvds(struct sun4i_tcon *tcon,
u8 clk_delay;
u32 reg, val = 0;
+ WARN_ON(!tcon->quirks->has_channel_0);
+
tcon->dclk_min_div = 7;
tcon->dclk_max_div = 7;
sun4i_tcon0_mode_set_common(tcon, mode);
@@ -344,6 +347,8 @@ static void sun4i_tcon0_mode_set_rgb(struct sun4i_tcon *tcon,
u8 clk_delay;
u32 val = 0;
+ WARN_ON(!tcon->quirks->has_channel_0);
+
tcon->dclk_min_div = 6;
tcon->dclk_max_div = 127;
sun4i_tcon0_mode_set_common(tcon, mode);
@@ -570,10 +575,12 @@ static int sun4i_tcon_init_clocks(struct device *dev,
}
clk_prepare_enable(tcon->clk);
- tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
- if (IS_ERR(tcon->sclk0)) {
- dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
- return PTR_ERR(tcon->sclk0);
+ if (tcon->quirks->has_channel_0) {
+ tcon->sclk0 = devm_clk_get(dev, "tcon-ch0");
+ if (IS_ERR(tcon->sclk0)) {
+ dev_err(dev, "Couldn't get the TCON channel 0 clock\n");
+ return PTR_ERR(tcon->sclk0);
+ }
}
if (tcon->quirks->has_channel_1) {
@@ -930,10 +937,12 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
goto err_free_clocks;
}
- ret = sun4i_dclk_create(dev, tcon);
- if (ret) {
- dev_err(dev, "Couldn't create our TCON dot clock\n");
- goto err_free_clocks;
+ if (tcon->quirks->has_channel_0) {
+ ret = sun4i_dclk_create(dev, tcon);
+ if (ret) {
+ dev_err(dev, "Couldn't create our TCON dot clock\n");
+ goto err_free_clocks;
+ }
}
ret = sun4i_tcon_init_irq(dev, tcon);
@@ -991,7 +1000,8 @@ static int sun4i_tcon_bind(struct device *dev, struct device *master,
return 0;
err_free_dotclock:
- sun4i_dclk_free(tcon);
+ if (tcon->quirks->has_channel_0)
+ sun4i_dclk_free(tcon);
err_free_clocks:
sun4i_tcon_free_clocks(tcon);
err_assert_reset:
@@ -1005,7 +1015,8 @@ static void sun4i_tcon_unbind(struct device *dev, struct device *master,
struct sun4i_tcon *tcon = dev_get_drvdata(dev);
list_del(&tcon->list);
- sun4i_dclk_free(tcon);
+ if (tcon->quirks->has_channel_0)
+ sun4i_dclk_free(tcon);
sun4i_tcon_free_clocks(tcon);
}
@@ -1102,16 +1113,19 @@ static int sun6i_tcon_set_mux(struct sun4i_tcon *tcon,
}
static const struct sun4i_tcon_quirks sun4i_a10_quirks = {
+ .has_channel_0 = true,
.has_channel_1 = true,
.set_mux = sun4i_a10_tcon_set_mux,
};
static const struct sun4i_tcon_quirks sun5i_a13_quirks = {
+ .has_channel_0 = true,
.has_channel_1 = true,
.set_mux = sun5i_a13_tcon_set_mux,
};
static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
+ .has_channel_0 = true,
.has_channel_1 = true,
.has_lvds_alt = true,
.needs_de_be_mux = true,
@@ -1119,26 +1133,29 @@ static const struct sun4i_tcon_quirks sun6i_a31_quirks = {
};
static const struct sun4i_tcon_quirks sun6i_a31s_quirks = {
+ .has_channel_0 = true,
.has_channel_1 = true,
.needs_de_be_mux = true,
};
static const struct sun4i_tcon_quirks sun7i_a20_quirks = {
+ .has_channel_0 = true,
.has_channel_1 = true,
/* Same display pipeline structure as A10 */
.set_mux = sun4i_a10_tcon_set_mux,
};
static const struct sun4i_tcon_quirks sun8i_a33_quirks = {
+ .has_channel_0 = true,
.has_lvds_alt = true,
};
static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
- /* nothing is supported */
+ .has_channel_0 = true,
};
static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
- /* nothing is supported */
+ .has_channel_0 = true,
};
/* sun4i_drv uses this list to check if a device node is a TCON */
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.h b/drivers/gpu/drm/sun4i/sun4i_tcon.h
index b761c7b823c5..78d55e7cd2b3 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.h
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.h
@@ -172,6 +172,7 @@
struct sun4i_tcon;
struct sun4i_tcon_quirks {
+ bool has_channel_0; /* a83t does not have channel 0 on second TCON */
bool has_channel_1; /* a33 does not have channel 1 */
bool has_lvds_alt; /* Does the LVDS clock have a parent other than the TCON clock? */
bool needs_de_be_mux; /* sun6i needs mux to select backend */
--
2.15.1
^ permalink raw reply related
* [PATCH v2 08/12] drm/sun4i: Add support for A83T second TCON
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
This TCON is connected to HDMI encoder.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun4i_tcon.c | 5 +++++
1 file changed, 5 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun4i_tcon.c b/drivers/gpu/drm/sun4i/sun4i_tcon.c
index 0815c528d08e..adfa39f372cf 100644
--- a/drivers/gpu/drm/sun4i/sun4i_tcon.c
+++ b/drivers/gpu/drm/sun4i/sun4i_tcon.c
@@ -1154,6 +1154,10 @@ static const struct sun4i_tcon_quirks sun8i_a83t_lcd_quirks = {
.has_channel_0 = true,
};
+static const struct sun4i_tcon_quirks sun8i_a83t_tv_quirks = {
+ .has_channel_1 = true,
+};
+
static const struct sun4i_tcon_quirks sun8i_v3s_quirks = {
.has_channel_0 = true,
};
@@ -1167,6 +1171,7 @@ const struct of_device_id sun4i_tcon_of_table[] = {
{ .compatible = "allwinner,sun7i-a20-tcon", .data = &sun7i_a20_quirks },
{ .compatible = "allwinner,sun8i-a33-tcon", .data = &sun8i_a33_quirks },
{ .compatible = "allwinner,sun8i-a83t-tcon-lcd", .data = &sun8i_a83t_lcd_quirks },
+ { .compatible = "allwinner,sun8i-a83t-tcon-tv", .data = &sun8i_a83t_tv_quirks },
{ .compatible = "allwinner,sun8i-v3s-tcon", .data = &sun8i_v3s_quirks },
{ }
};
--
2.15.1
^ permalink raw reply related
* [PATCH v2 09/12] drm/sun4i: Add support for A83T second DE2 mixer
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
It supports 1 VI and 1 UI plane and HW scaling on both planes.
Acked-by: Maxime Ripard <maxime.ripard@free-electrons.com>
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/sun8i_mixer.c | 11 +++++++++++
1 file changed, 11 insertions(+)
diff --git a/drivers/gpu/drm/sun4i/sun8i_mixer.c b/drivers/gpu/drm/sun4i/sun8i_mixer.c
index 2cbb2de6d39c..9b0256d31a61 100644
--- a/drivers/gpu/drm/sun4i/sun8i_mixer.c
+++ b/drivers/gpu/drm/sun4i/sun8i_mixer.c
@@ -485,6 +485,13 @@ static const struct sun8i_mixer_cfg sun8i_a83t_mixer0_cfg = {
.vi_num = 1,
};
+static const struct sun8i_mixer_cfg sun8i_a83t_mixer1_cfg = {
+ .ccsc = 1,
+ .scaler_mask = 0x3,
+ .ui_num = 1,
+ .vi_num = 1,
+};
+
static const struct sun8i_mixer_cfg sun8i_v3s_mixer_cfg = {
.vi_num = 2,
.ui_num = 1,
@@ -498,6 +505,10 @@ static const struct of_device_id sun8i_mixer_of_table[] = {
.compatible = "allwinner,sun8i-a83t-de2-mixer-0",
.data = &sun8i_a83t_mixer0_cfg,
},
+ {
+ .compatible = "allwinner,sun8i-a83t-de2-mixer-1",
+ .data = &sun8i_a83t_mixer1_cfg,
+ },
{
.compatible = "allwinner,sun8i-v3s-de2-mixer",
.data = &sun8i_v3s_mixer_cfg,
--
2.15.1
^ permalink raw reply related
* [PATCH v2 10/12] drm/sun4i: Implement A83T HDMI driver
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
A83T has DW HDMI IP block with a custom PHY similar to Synopsys gen2
HDMI PHY.
Only video output was tested, while HW also supports audio and CEC.
Support for them will be added later.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
drivers/gpu/drm/sun4i/Kconfig | 9 +
drivers/gpu/drm/sun4i/Makefile | 4 +
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c | 183 ++++++++++++++++++++
drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h | 51 ++++++
drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c | 302 +++++++++++++++++++++++++++++++++
5 files changed, 549 insertions(+)
create mode 100644 drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
create mode 100644 drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
create mode 100644 drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
diff --git a/drivers/gpu/drm/sun4i/Kconfig b/drivers/gpu/drm/sun4i/Kconfig
index 882d85db9053..7327da3bc94f 100644
--- a/drivers/gpu/drm/sun4i/Kconfig
+++ b/drivers/gpu/drm/sun4i/Kconfig
@@ -40,6 +40,15 @@ config DRM_SUN4I_BACKEND
do some alpha blending and feed graphics to TCON. If M is
selected the module will be called sun4i-backend.
+config DRM_SUN8I_DW_HDMI
+ tristate "Support for Allwinner version of DesignWare HDMI"
+ depends on DRM_SUN4I
+ select DRM_DW_HDMI
+ help
+ Choose this option if you have an Allwinner SoC with the
+ DesignWare HDMI controller with custom HDMI PHY. If M is
+ selected the module will be called sun8i_dw_hdmi.
+
config DRM_SUN8I_MIXER
tristate "Support for Allwinner Display Engine 2.0 Mixer"
default MACH_SUN8I
diff --git a/drivers/gpu/drm/sun4i/Makefile b/drivers/gpu/drm/sun4i/Makefile
index 2b37a6abbb1d..a7c47d9aa64d 100644
--- a/drivers/gpu/drm/sun4i/Makefile
+++ b/drivers/gpu/drm/sun4i/Makefile
@@ -9,6 +9,9 @@ sun4i-drm-hdmi-y += sun4i_hdmi_enc.o
sun4i-drm-hdmi-y += sun4i_hdmi_i2c.o
sun4i-drm-hdmi-y += sun4i_hdmi_tmds_clk.o
+sun8i-drm-hdmi-y += sun8i_dw_hdmi.o
+sun8i-drm-hdmi-y += sun8i_hdmi_phy.o
+
sun8i-mixer-y += sun8i_mixer.o sun8i_ui_layer.o \
sun8i_vi_layer.o sun8i_ui_scaler.o \
sun8i_vi_scaler.o sun8i_csc.o
@@ -26,4 +29,5 @@ obj-$(CONFIG_DRM_SUN4I) += sun6i_drc.o
obj-$(CONFIG_DRM_SUN4I_BACKEND) += sun4i-backend.o
obj-$(CONFIG_DRM_SUN4I_HDMI) += sun4i-drm-hdmi.o
+obj-$(CONFIG_DRM_SUN8I_DW_HDMI) += sun8i-drm-hdmi.o
obj-$(CONFIG_DRM_SUN8I_MIXER) += sun8i-mixer.o
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
new file mode 100644
index 000000000000..afb9f5f988a9
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.c
@@ -0,0 +1,183 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/component.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+
+#include <drm/drm_of.h>
+#include <drm/drmP.h>
+#include <drm/drm_crtc_helper.h>
+
+#include "sun8i_dw_hdmi.h"
+
+static void sun8i_dw_hdmi_encoder_mode_set(struct drm_encoder *encoder,
+ struct drm_display_mode *mode,
+ struct drm_display_mode *adj_mode)
+{
+ struct sun8i_dw_hdmi *hdmi = encoder_to_sun8i_dw_hdmi(encoder);
+
+ sun8i_hdmi_phy_update_clock(hdmi->phy, mode->crtc_clock * 1000);
+}
+
+static const struct drm_encoder_helper_funcs
+sun8i_dw_hdmi_encoder_helper_funcs = {
+ .mode_set = sun8i_dw_hdmi_encoder_mode_set,
+};
+
+static const struct drm_encoder_funcs sun8i_dw_hdmi_encoder_funcs = {
+ .destroy = drm_encoder_cleanup,
+};
+
+static enum drm_mode_status
+sun8i_dw_hdmi_mode_valid(struct drm_connector *connector,
+ const struct drm_display_mode *mode)
+{
+ if (mode->clock > 297000)
+ return MODE_BAD;
+
+ return MODE_OK;
+}
+
+static void sun8i_dw_hdmi_deinit(const struct dw_hdmi_plat_data *plat_data)
+{
+ struct sun8i_dw_hdmi *hdmi = plat_data_to_sun8i_dw_hdmi(plat_data);
+
+ sun8i_hdmi_phy_remove(hdmi);
+
+ reset_control_assert(hdmi->rst_ctrl);
+}
+
+static int sun8i_dw_hdmi_bind(struct device *dev, struct device *master,
+ void *data)
+{
+ struct platform_device *pdev = to_platform_device(dev);
+ struct dw_hdmi_plat_data *plat_data;
+ struct drm_device *drm = data;
+ struct device_node *phy_node;
+ struct drm_encoder *encoder;
+ struct sun8i_dw_hdmi *hdmi;
+ int ret;
+
+ if (!pdev->dev.of_node)
+ return -ENODEV;
+
+ hdmi = devm_kzalloc(&pdev->dev, sizeof(*hdmi), GFP_KERNEL);
+ if (!hdmi)
+ return -ENOMEM;
+
+ plat_data = &hdmi->plat_data;
+ hdmi->dev = &pdev->dev;
+ encoder = &hdmi->encoder;
+
+ encoder->possible_crtcs = drm_of_find_possible_crtcs(drm, dev->of_node);
+ /*
+ * If we failed to find the CRTC(s) which this encoder is
+ * supposed to be connected to, it's because the CRTC has
+ * not been registered yet. Defer probing, and hope that
+ * the required CRTC is added later.
+ */
+ if (encoder->possible_crtcs == 0)
+ return -EPROBE_DEFER;
+
+ hdmi->rst_ctrl = devm_reset_control_get(dev, "ctrl");
+ if (IS_ERR(hdmi->rst_ctrl)) {
+ dev_err(dev, "Could not get ctrl reset control\n");
+ return PTR_ERR(hdmi->rst_ctrl);
+ }
+
+ ret = reset_control_deassert(hdmi->rst_ctrl);
+ if (ret) {
+ dev_err(dev, "Could not deassert ctrl reset control\n");
+ return ret;
+ }
+
+ phy_node = of_parse_phandle(dev->of_node, "phys", 0);
+ if (!phy_node) {
+ dev_err(dev, "Can't found PHY phandle\n");
+ goto err_assert_ctrl_reset;
+ }
+
+ ret = sun8i_hdmi_phy_probe(hdmi, phy_node);
+ of_node_put(phy_node);
+ if (ret) {
+ dev_err(dev, "Couldn't get the HDMI PHY\n");
+ goto err_assert_ctrl_reset;
+ }
+
+ drm_encoder_helper_add(encoder, &sun8i_dw_hdmi_encoder_helper_funcs);
+ drm_encoder_init(drm, encoder, &sun8i_dw_hdmi_encoder_funcs,
+ DRM_MODE_ENCODER_TMDS, NULL);
+
+ sun8i_hdmi_phy_init(hdmi->phy);
+
+ plat_data->deinit = &sun8i_dw_hdmi_deinit;
+ plat_data->mode_valid = &sun8i_dw_hdmi_mode_valid;
+ plat_data->phy_ops = sun8i_hdmi_phy_get_ops();
+ plat_data->phy_name = "sun8i_dw_hdmi_phy";
+ plat_data->phy_data = hdmi->phy;
+
+ ret = dw_hdmi_bind(pdev, encoder, plat_data);
+
+ /*
+ * If dw_hdmi_bind() fails we'll never call dw_hdmi_unbind(),
+ * which would have called the encoder cleanup. Do it manually.
+ */
+ if (ret)
+ goto cleanup_encoder;
+
+ return 0;
+
+cleanup_encoder:
+ drm_encoder_cleanup(encoder);
+ sun8i_hdmi_phy_remove(hdmi);
+err_assert_ctrl_reset:
+ reset_control_assert(hdmi->rst_ctrl);
+
+ return ret;
+}
+
+static void sun8i_dw_hdmi_unbind(struct device *dev, struct device *master,
+ void *data)
+{
+ return dw_hdmi_unbind(dev);
+}
+
+static const struct component_ops sun8i_dw_hdmi_ops = {
+ .bind = sun8i_dw_hdmi_bind,
+ .unbind = sun8i_dw_hdmi_unbind,
+};
+
+static int sun8i_dw_hdmi_probe(struct platform_device *pdev)
+{
+ return component_add(&pdev->dev, &sun8i_dw_hdmi_ops);
+}
+
+static int sun8i_dw_hdmi_remove(struct platform_device *pdev)
+{
+ component_del(&pdev->dev, &sun8i_dw_hdmi_ops);
+
+ return 0;
+}
+
+static const struct of_device_id sun8i_dw_hdmi_dt_ids[] = {
+ { .compatible = "allwinner,sun8i-a83t-dw-hdmi" },
+ { /* sentinel */ },
+};
+MODULE_DEVICE_TABLE(of, sun8i_dw_hdmi_dt_ids);
+
+struct platform_driver sun8i_dw_hdmi_pltfm_driver = {
+ .probe = sun8i_dw_hdmi_probe,
+ .remove = sun8i_dw_hdmi_remove,
+ .driver = {
+ .name = "sun8i-dw-hdmi",
+ .of_match_table = sun8i_dw_hdmi_dt_ids,
+ },
+};
+module_platform_driver(sun8i_dw_hdmi_pltfm_driver);
+
+MODULE_AUTHOR("Jernej Skrabec <jernej.skrabec@siol.net>");
+MODULE_DESCRIPTION("Allwinner DW HDMI bridge");
+MODULE_LICENSE("GPL");
diff --git a/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
new file mode 100644
index 000000000000..77a97f199333
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_dw_hdmi.h
@@ -0,0 +1,51 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (C) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#ifndef _SUN8I_DW_HDMI_H_
+#define _SUN8I_DW_HDMI_H_
+
+#include <drm/bridge/dw_hdmi.h>
+#include <drm/drm_encoder.h>
+#include <linux/clk.h>
+#include <linux/regmap.h>
+#include <linux/reset.h>
+
+struct sun8i_hdmi_phy {
+ struct clk *clk_bus;
+ struct clk *clk_mod;
+ struct clk *clk_tmds;
+ struct regmap *regs;
+ struct reset_control *rst_phy;
+};
+
+struct sun8i_dw_hdmi {
+ struct device *dev;
+ struct drm_encoder encoder;
+ struct sun8i_hdmi_phy *phy;
+ struct dw_hdmi_plat_data plat_data;
+ struct reset_control *rst_ctrl;
+};
+
+static inline struct sun8i_dw_hdmi *
+encoder_to_sun8i_dw_hdmi(struct drm_encoder *encoder)
+{
+ return container_of(encoder, struct sun8i_dw_hdmi, encoder);
+}
+
+static inline struct sun8i_dw_hdmi *
+plat_data_to_sun8i_dw_hdmi(const struct dw_hdmi_plat_data *plat_data)
+{
+ return container_of(plat_data, struct sun8i_dw_hdmi, plat_data);
+}
+
+int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node);
+void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi);
+
+void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy);
+const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void);
+void sun8i_hdmi_phy_update_clock(struct sun8i_hdmi_phy *phy,
+ unsigned long rate);
+
+#endif /* _SUN8I_DW_HDMI_H_ */
diff --git a/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
new file mode 100644
index 000000000000..2555e488c5c5
--- /dev/null
+++ b/drivers/gpu/drm/sun4i/sun8i_hdmi_phy.c
@@ -0,0 +1,302 @@
+// SPDX-License-Identifier: GPL-2.0+
+/*
+ * Copyright (c) 2018 Jernej Skrabec <jernej.skrabec@siol.net>
+ */
+
+#include <linux/of_address.h>
+
+#include "sun8i_dw_hdmi.h"
+
+#define SUN8I_HDMI_PHY_DBG_CTRL_REG 0x0000
+#define SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK BIT(0)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK GENMASK(15, 8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_POL(val) (val << 8)
+#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK GENMASK(23, 16)
+#define SUN8I_HDMI_PHY_DBG_CTRL_ADDR(addr) (addr << 16)
+
+#define SUN8I_HDMI_PHY_REXT_CTRL_REG 0x0004
+#define SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN BIT(31)
+
+#define SUN8I_HDMI_PHY_READ_EN_REG 0x0010
+#define SUN8I_HDMI_PHY_READ_EN_MAGIC 0x54524545
+
+#define SUN8I_HDMI_PHY_UNSCRAMBLE_REG 0x0014
+#define SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC 0x42494E47
+
+/*
+ * Address can be actually any value. Here is set to same value as
+ * it is set in BSP driver.
+ */
+#define I2C_ADDR 0x69
+
+static int sun8i_hdmi_phy_config(struct dw_hdmi *hdmi, void *data,
+ struct drm_display_mode *mode)
+{
+ struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
+ u32 val = 0;
+ int ret;
+
+ ret = clk_enable(phy->clk_tmds);
+ if (ret)
+ return ret;
+
+ if ((mode->flags & DRM_MODE_FLAG_NHSYNC) &&
+ (mode->flags & DRM_MODE_FLAG_NHSYNC)) {
+ val = 0x03;
+ }
+
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
+ SUN8I_HDMI_PHY_DBG_CTRL_POL_MASK,
+ SUN8I_HDMI_PHY_DBG_CTRL_POL(val));
+
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
+ SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN,
+ SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN);
+
+ /* power down */
+ dw_hdmi_phy_gen2_txpwron(hdmi, 0);
+ dw_hdmi_phy_gen2_pddq(hdmi, 1);
+
+ dw_hdmi_phy_reset(hdmi);
+
+ dw_hdmi_phy_gen2_pddq(hdmi, 0);
+
+ dw_hdmi_phy_i2c_set_addr(hdmi, I2C_ADDR);
+
+ /*
+ * Values are taken from BSP HDMI driver. Although AW didn't
+ * release any documentation, explanation of this values can
+ * be found in i.MX 6Dual/6Quad Reference Manual.
+ */
+ if (mode->crtc_clock <= 27000) {
+ dw_hdmi_phy_i2c_write(hdmi, 0x01e0, 0x06);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x15);
+ dw_hdmi_phy_i2c_write(hdmi, 0x08da, 0x10);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0318, 0x0e);
+ dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ } else if (mode->crtc_clock <= 74250) {
+ dw_hdmi_phy_i2c_write(hdmi, 0x0540, 0x06);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0005, 0x15);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0007, 0x19);
+ dw_hdmi_phy_i2c_write(hdmi, 0x02b5, 0x0e);
+ dw_hdmi_phy_i2c_write(hdmi, 0x8009, 0x09);
+ } else if (mode->crtc_clock <= 148500) {
+ dw_hdmi_phy_i2c_write(hdmi, 0x04a0, 0x06);
+ dw_hdmi_phy_i2c_write(hdmi, 0x000a, 0x15);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0021, 0x0e);
+ dw_hdmi_phy_i2c_write(hdmi, 0x8029, 0x09);
+ } else {
+ dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x06);
+ dw_hdmi_phy_i2c_write(hdmi, 0x000f, 0x15);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x10);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0002, 0x19);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x0e);
+ dw_hdmi_phy_i2c_write(hdmi, 0x802b, 0x09);
+ }
+
+ dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x1e);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x13);
+ dw_hdmi_phy_i2c_write(hdmi, 0x0000, 0x17);
+
+ dw_hdmi_phy_gen2_txpwron(hdmi, 1);
+
+ return 0;
+};
+
+static void sun8i_hdmi_phy_disable(struct dw_hdmi *hdmi, void *data)
+{
+ struct sun8i_hdmi_phy *phy = (struct sun8i_hdmi_phy *)data;
+
+ dw_hdmi_phy_gen2_txpwron(hdmi, 0);
+ dw_hdmi_phy_gen2_pddq(hdmi, 1);
+
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_REXT_CTRL_REG,
+ SUN8I_HDMI_PHY_REXT_CTRL_REXT_EN, 0);
+
+ clk_disable(phy->clk_tmds);
+}
+
+static const struct dw_hdmi_phy_ops sun8i_hdmi_phy_ops = {
+ .init = &sun8i_hdmi_phy_config,
+ .disable = &sun8i_hdmi_phy_disable,
+ .read_hpd = &dw_hdmi_phy_read_hpd,
+ .update_hpd = &dw_hdmi_phy_update_hpd,
+ .setup_hpd = &dw_hdmi_phy_setup_hpd,
+};
+
+void sun8i_hdmi_phy_init(struct sun8i_hdmi_phy *phy)
+{
+ /* enable read access to HDMI controller */
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_READ_EN_REG,
+ SUN8I_HDMI_PHY_READ_EN_MAGIC);
+
+ /* unscramble register offsets */
+ regmap_write(phy->regs, SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
+ SUN8I_HDMI_PHY_UNSCRAMBLE_MAGIC);
+
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
+ SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK,
+ SUN8I_HDMI_PHY_DBG_CTRL_PX_LOCK);
+
+ /*
+ * Set PHY I2C address. It must match to the address set by
+ * dw_hdmi_phy_set_slave_addr().
+ */
+ regmap_update_bits(phy->regs, SUN8I_HDMI_PHY_DBG_CTRL_REG,
+ SUN8I_HDMI_PHY_DBG_CTRL_ADDR_MASK,
+ SUN8I_HDMI_PHY_DBG_CTRL_ADDR(I2C_ADDR));
+}
+
+const struct dw_hdmi_phy_ops *sun8i_hdmi_phy_get_ops(void)
+{
+ return &sun8i_hdmi_phy_ops;
+}
+
+void sun8i_hdmi_phy_update_clock(struct sun8i_hdmi_phy *phy,
+ unsigned long rate)
+{
+ clk_set_rate(phy->clk_tmds, rate);
+}
+
+static struct regmap_config sun8i_hdmi_phy_regmap_config = {
+ .reg_bits = 32,
+ .val_bits = 32,
+ .reg_stride = 4,
+ .max_register = SUN8I_HDMI_PHY_UNSCRAMBLE_REG,
+ .name = "phy"
+};
+
+static const struct of_device_id sun8i_hdmi_phy_of_table[] = {
+ { .compatible = "allwinner,sun8i-a83t-hdmi-phy" },
+ { /* sentinel */ }
+};
+
+int sun8i_hdmi_phy_probe(struct sun8i_dw_hdmi *hdmi, struct device_node *node)
+{
+ struct device *dev = hdmi->dev;
+ struct sun8i_hdmi_phy *phy;
+ struct resource res;
+ void __iomem *regs;
+ int ret;
+
+ if (!of_match_node(sun8i_hdmi_phy_of_table, node)) {
+ dev_err(dev, "Incompatible HDMI PHY\n");
+ return -EINVAL;
+ }
+
+ phy = devm_kzalloc(dev, sizeof(*phy), GFP_KERNEL);
+ if (!phy)
+ return -ENOMEM;
+
+ ret = of_address_to_resource(node, 0, &res);
+ if (ret) {
+ dev_err(dev, "phy: Couldn't get our resources\n");
+ return ret;
+ }
+
+ regs = devm_ioremap_resource(dev, &res);
+ if (IS_ERR(regs)) {
+ dev_err(dev, "Couldn't map the HDMI PHY registers\n");
+ return PTR_ERR(regs);
+ }
+
+ phy->regs = devm_regmap_init_mmio(dev, regs,
+ &sun8i_hdmi_phy_regmap_config);
+ if (IS_ERR(phy->regs)) {
+ dev_err(dev, "Couldn't create the HDMI PHY regmap\n");
+ return PTR_ERR(phy->regs);
+ }
+
+ phy->clk_bus = of_clk_get_by_name(node, "bus");
+ if (IS_ERR(phy->clk_bus)) {
+ dev_err(dev, "Could not get bus clock\n");
+ return PTR_ERR(phy->clk_bus);
+ }
+
+ phy->clk_mod = of_clk_get_by_name(node, "mod");
+ if (IS_ERR(phy->clk_mod)) {
+ dev_err(dev, "Could not get mod clock\n");
+ ret = PTR_ERR(phy->clk_mod);
+ goto err_put_clk_bus;
+ }
+
+ phy->clk_tmds = of_clk_get_by_name(node, "tmds");
+ if (IS_ERR(phy->clk_tmds)) {
+ dev_err(dev, "Could not get tmds clock\n");
+ ret = PTR_ERR(phy->clk_tmds);
+ goto err_put_clk_mod;
+ }
+
+ phy->rst_phy = of_reset_control_get_shared(node, "phy");
+ if (IS_ERR(phy->rst_phy)) {
+ dev_err(dev, "Could not get phy reset control\n");
+ ret = PTR_ERR(phy->rst_phy);
+ goto err_put_clk_tmds;
+ }
+
+ ret = reset_control_deassert(phy->rst_phy);
+ if (ret) {
+ dev_err(dev, "Cannot deassert phy reset control: %d\n", ret);
+ goto err_put_rst_phy;
+ }
+
+ ret = clk_prepare_enable(phy->clk_bus);
+ if (ret) {
+ dev_err(dev, "Cannot enable bus clock: %d\n", ret);
+ goto err_deassert_rst_phy;
+ }
+
+ ret = clk_prepare_enable(phy->clk_mod);
+ if (ret) {
+ dev_err(dev, "Cannot enable mod clock: %d\n", ret);
+ goto err_disable_clk_bus;
+ }
+
+ ret = clk_prepare(phy->clk_tmds);
+ if (ret) {
+ dev_err(dev, "Cannot prepare tmds clock: %d\n", ret);
+ goto err_disable_clk_mod;
+ }
+
+ hdmi->phy = phy;
+
+ return 0;
+
+err_disable_clk_mod:
+ clk_disable_unprepare(phy->clk_mod);
+err_disable_clk_bus:
+ clk_disable_unprepare(phy->clk_bus);
+err_deassert_rst_phy:
+ reset_control_assert(phy->rst_phy);
+err_put_rst_phy:
+ reset_control_put(phy->rst_phy);
+err_put_clk_tmds:
+ clk_put(phy->clk_tmds);
+err_put_clk_mod:
+ clk_put(phy->clk_mod);
+err_put_clk_bus:
+ clk_put(phy->clk_bus);
+
+ return ret;
+}
+
+void sun8i_hdmi_phy_remove(struct sun8i_dw_hdmi *hdmi)
+{
+ struct sun8i_hdmi_phy *phy = hdmi->phy;
+
+ clk_unprepare(phy->clk_tmds);
+ clk_disable_unprepare(phy->clk_mod);
+ clk_disable_unprepare(phy->clk_bus);
+
+ reset_control_assert(phy->rst_phy);
+
+ reset_control_put(phy->rst_phy);
+
+ clk_put(phy->clk_tmds);
+ clk_put(phy->clk_mod);
+ clk_put(phy->clk_bus);
+}
--
2.15.1
^ permalink raw reply related
* [PATCH v2 11/12] ARM: dts: sun8i: a83t: Add HDMI display pipeline
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
This commit adds all bits necessary for HDMI on A83T - mixer1, tcon1,
hdmi, hdmi phy and hdmi pinctrl entries.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm/boot/dts/sun8i-a83t.dtsi | 119 +++++++++++++++++++++++++++++++++++++-
1 file changed, 118 insertions(+), 1 deletion(-)
diff --git a/arch/arm/boot/dts/sun8i-a83t.dtsi b/arch/arm/boot/dts/sun8i-a83t.dtsi
index 7f4955a5fab7..c2638966d338 100644
--- a/arch/arm/boot/dts/sun8i-a83t.dtsi
+++ b/arch/arm/boot/dts/sun8i-a83t.dtsi
@@ -155,7 +155,7 @@
de: display-engine {
compatible = "allwinner,sun8i-a83t-display-engine";
- allwinner,pipelines = <&mixer0>;
+ allwinner,pipelines = <&mixer0>, <&mixer1>;
status = "disabled";
};
@@ -208,6 +208,32 @@
};
};
+ mixer1: mixer at 1200000 {
+ compatible = "allwinner,sun8i-a83t-de2-mixer-1";
+ reg = <0x01200000 0x100000>;
+ clocks = <&display_clocks CLK_BUS_MIXER1>,
+ <&display_clocks CLK_MIXER1>;
+ clock-names = "bus",
+ "mod";
+ resets = <&display_clocks RST_WB>;
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ mixer1_out: port at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ mixer1_out_tcon1: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&tcon1_in_mixer1>;
+ };
+ };
+ };
+ };
+
syscon: syscon at 1c00000 {
compatible = "allwinner,sun8i-a83t-system-controller",
"syscon";
@@ -256,6 +282,43 @@
};
};
+ tcon1: lcd-controller at 1c0d000 {
+ compatible = "allwinner,sun8i-a83t-tcon-tv";
+ reg = <0x01c0d000 0x1000>;
+ interrupts = <GIC_SPI 87 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_TCON1>, <&ccu CLK_TCON1>;
+ clock-names = "ahb", "tcon-ch1";
+ resets = <&ccu RST_BUS_TCON1>;
+ reset-names = "lcd";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ tcon1_in: port at 0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ tcon1_in_mixer1: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&mixer1_out_tcon1>;
+ };
+ };
+
+ tcon1_out: port at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+
+ tcon1_out_hdmi: endpoint at 1 {
+ reg = <1>;
+ remote-endpoint = <&hdmi_in_tcon1>;
+ };
+ };
+ };
+ };
+
mmc0: mmc at 1c0f000 {
compatible = "allwinner,sun8i-a83t-mmc",
"allwinner,sun7i-a20-mmc";
@@ -427,6 +490,11 @@
drive-strength = <40>;
};
+ hdmi_pins: hdmi-pins {
+ pins = "PH6", "PH7", "PH8";
+ function = "hdmi";
+ };
+
i2c0_pins: i2c0-pins {
pins = "PH0", "PH1";
function = "i2c0";
@@ -685,6 +753,55 @@
interrupts = <GIC_PPI 9 (GIC_CPU_MASK_SIMPLE(8) | IRQ_TYPE_LEVEL_HIGH)>;
};
+ hdmi: hdmi at 1ee0000 {
+ compatible = "allwinner,sun8i-a83t-dw-hdmi";
+ reg = <0x01ee0000 0x10000>;
+ reg-io-width = <1>;
+ interrupts = <GIC_SPI 88 IRQ_TYPE_LEVEL_HIGH>;
+ clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_SLOW>;
+ clock-names = "iahb", "isfr";
+ resets = <&ccu RST_BUS_HDMI1>;
+ reset-names = "ctrl";
+ phys = <&hdmi_phy>;
+ phy-names = "hdmi-phy";
+ pinctrl-names = "default";
+ pinctrl-0 = <&hdmi_pins>;
+ status = "disabled";
+
+ ports {
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ hdmi_in: port at 0 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <0>;
+
+ hdmi_in_tcon1: endpoint at 0 {
+ reg = <0>;
+ remote-endpoint = <&tcon1_out_hdmi>;
+ };
+ };
+
+ hdmi_out: port at 1 {
+ #address-cells = <1>;
+ #size-cells = <0>;
+ reg = <1>;
+ };
+ };
+ };
+
+ hdmi_phy: hdmi-phy at 1ef0000 {
+ compatible = "allwinner,sun8i-a83t-hdmi-phy";
+ reg = <0x01ef0000 0x10000>;
+ clocks = <&ccu CLK_BUS_HDMI>, <&ccu CLK_HDMI_SLOW>,
+ <&ccu CLK_HDMI>;
+ clock-names = "bus", "mod", "tmds";
+ resets = <&ccu RST_BUS_HDMI0>;
+ reset-names = "phy";
+ #phy-cells = <0>;
+ };
+
r_intc: interrupt-controller at 1f00c00 {
compatible = "allwinner,sun8i-a83t-r-intc",
"allwinner,sun6i-a31-r-intc";
--
2.15.1
^ permalink raw reply related
* [PATCH v2 12/12] ARM: dts: sun8i: a83t: Enable HDMI on BananaPi M3
From: Jernej Skrabec @ 2018-01-10 19:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110192512.19684-1-jernej.skrabec@siol.net>
BananaPi M3 includes HDMI connector, so add support for it.
Signed-off-by: Jernej Skrabec <jernej.skrabec@siol.net>
---
arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts | 25 +++++++++++++++++++++++++
1 file changed, 25 insertions(+)
diff --git a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
index 6550bf0e594b..00e47423cd07 100644
--- a/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
+++ b/arch/arm/boot/dts/sun8i-a83t-bananapi-m3.dts
@@ -60,6 +60,17 @@
stdout-path = "serial0:115200n8";
};
+ connector {
+ compatible = "hdmi-connector";
+ type = "a";
+
+ port {
+ hdmi_con_in: endpoint {
+ remote-endpoint = <&hdmi_out_con>;
+ };
+ };
+ };
+
reg_usb1_vbus: reg-usb1-vbus {
compatible = "regulator-fixed";
regulator-name = "usb1-vbus";
@@ -82,6 +93,10 @@
};
};
+&de {
+ status = "okay";
+};
+
&ehci0 {
/* Terminus Tech FE 1.1s 4-port USB 2.0 hub here */
status = "okay";
@@ -100,6 +115,16 @@
status = "okay";
};
+&hdmi {
+ status = "okay";
+};
+
+&hdmi_out {
+ hdmi_out_con: endpoint {
+ remote-endpoint = <&hdmi_con_in>;
+ };
+};
+
&mdio {
rgmii_phy: ethernet-phy at 1 {
compatible = "ethernet-phy-ieee802.3-c22";
--
2.15.1
^ permalink raw reply related
* [PATCH v3 02/13] arm64: Kconfig: Reword UNMAP_KERNEL_AT_EL0 kconfig entry
From: Will Deacon @ 2018-01-10 19:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180109171700.GA18100@infradead.org>
On Tue, Jan 09, 2018 at 09:17:00AM -0800, Christoph Hellwig wrote:
> On Mon, Jan 08, 2018 at 05:32:27PM +0000, Will Deacon wrote:
> > Although CONFIG_UNMAP_KERNEL_AT_EL0 does make KASLR more robust, it's
> > actually more useful as a mitigation against speculation attacks that
> > can leak arbitrary kernel data to userspace through speculation.
> >
> > Reword the Kconfig help message to reflect this, and make the option
> > depend on EXPERT so that it is on by default for the majority of users.
>
> I still haven't heard an anwer on why this isn't using
> CONFIG_PAGE_TABLE_ISOLATION but instead reinvents its own symbol.
Mainly because this code was written before CONFIG_PAGE_TABLE_ISOLATION had
been proposed and I wanted to avoid confusion with the ongoing backports
just to align on the naming for an arch-specific config option. We could
CONFIG_PAGE_TABLE_ISOLATION and make it select CONFIG_UNMAP_KERNEL_AT_EL) if
you like, but worth noting that this is default 'y' anyway and depends on
EXPERT.
Will
^ permalink raw reply
* [PATCH linux dev-4.10 0/6] Add support PECI and PECI hwmon drivers
From: Jae Hyun Yoo @ 2018-01-10 19:30 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110191703.GA20248@kroah.com>
On 1/10/2018 11:17 AM, Greg KH wrote:
> On Wed, Jan 10, 2018 at 11:14:34AM -0800, Jae Hyun Yoo wrote:
>> On 1/10/2018 2:17 AM, Greg KH wrote:
>>> On Tue, Jan 09, 2018 at 02:31:20PM -0800, Jae Hyun Yoo wrote:
>>>> From: Jae Hyun Yoo <jae.hyun.yoo@intel.com>
>>>>
>>>> Hello,
>>>>
>>>> This patch set provides support for PECI of AST2400/2500 which can give us PECI
>>>> functionalities such as temperature monitoring, platform manageability,
>>>> processor diagnostics and failure analysis. Also provides generic peci.h and
>>>> peci_ioctl.h headers to provide compatibility to peci drivers that can be
>>>> implemented later e.g. Nuvoton's BMC SoC family.
>>>
>>> What is the "dev-4.10" in the subject for? 4.10 is really old and
>>> obsolete :(
>>>
>>> thanks,
>>>
>>> greg k-h
>>>
>>
>> I made this patch set on top of the v4.10 which OpenBmc project is currently
>> using. I'll rebase this patch set onto the current kernel.org mainline.
>
> What is "OpenBmc", and why are they using an obsolete and insecure
> kernel for their project? That seems like a very foolish thing to do...
>
> thanks,
>
> greg k-h
>
OpenBmc is an open source project to create a highly extensible
framework for BMC (Board Management Controller) software for data-center
computer systems:
https://github.com/openbmc
Its current mainline is v4.10 but it is being kept upgrading so it will
be upgraded to the latest stable or long-term version soon.
Thanks,
Jae
^ permalink raw reply
* [PATCH linux dev-4.10 3/6] drivers/misc: Add driver for Aspeed PECI and generic PECI headers
From: Jae Hyun Yoo @ 2018-01-10 19:32 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110101840.GB5822@kroah.com>
On 1/10/2018 2:18 AM, Greg KH wrote:
> On Tue, Jan 09, 2018 at 02:31:23PM -0800, Jae Hyun Yoo wrote:
>> This commit adds driver implementation for Aspeed PECI. Also adds
>> generic peci.h and peci_ioctl.h files to provide compatibility
>> to peci drivers that can be implemented later e.g. Nuvoton's BMC
>> SoC family.
>
> We don't add code that could be used "sometime in the future". Only
> include stuff that we use now.
>
> Please fix up this series based on that and resubmit. There should not
> be any need for any uapi file then, right?
>
> thanks,
>
> greg k-h
>
These header files are being used in this patch set as well. I meant,
these files also can be used for the future implementation to provide
compatibility. I will update the commit message.
Thanks,
Jae
^ permalink raw reply
* [PATCH linux dev-4.10 3/6] drivers/misc: Add driver for Aspeed PECI and generic PECI headers
From: Jae Hyun Yoo @ 2018-01-10 19:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20180110102011.GC5822@kroah.com>
On 1/10/2018 2:20 AM, Greg KH wrote:
> On Tue, Jan 09, 2018 at 02:31:23PM -0800, Jae Hyun Yoo wrote:
>> +#pragma pack(push, 1)
>> +struct peci_xfer_msg {
>> + unsigned char client_addr;
>> + unsigned char tx_len;
>> + unsigned char rx_len;
>> + unsigned char tx_buf[MAX_BUFFER_SIZE];
>> + unsigned char rx_buf[MAX_BUFFER_SIZE];
>> +};
>> +#pragma pack(pop)
>
> For any structure that crosses the user/kernel boundry, you _HAVE_ to
> use the "__" variant. So for here you would use __u8 instead of
> "unsigned char" in order for things to work properly.
>
> I'm guessing you didn't test this all out on a mixed 32/64 bit system?
>
> Please fix up and test to ensure that it all works properly before
> resubmitting.
>
> thanks,
>
> greg k-h
>
Thanks for your pointing it out. I'll fix this.
Thanks a lot,
Jae
^ permalink raw reply
* [PATCH v2 2/2] phy: rockchip-emmc: use regmap_read_poll_timeout to poll dllrdy
From: Doug Anderson @ 2018-01-10 19:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515569879-31808-3-git-send-email-wxt@rock-chips.com>
Hi,
On Tue, Jan 9, 2018 at 11:37 PM, Caesar Wang <wxt@rock-chips.com> wrote:
> From: Shawn Lin <shawn.lin@rock-chips.com>
>
> Just use the API instead of open-coding it, no functional change
> intended.
>
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> Reviewed-by: Brian Norris <briannorris@chromium.org>
> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
>
> ---
>
> Changes in v2:
> - As Brian commented on https://patchwork.kernel.org/patch/10139891/,
> changed the note and added to print error value with
> regmap_read_poll_timeout API.
>
> drivers/phy/rockchip/phy-rockchip-emmc.c | 33 +++++++++++---------------------
> 1 file changed, 11 insertions(+), 22 deletions(-)
See comments in Shawn's v2. AKA: <https://patchwork.kernel.org/patch/10154797/>
^ permalink raw reply
* [PATCH v2 1/2] phy: rockchip-emmc: retry calpad busy trimming
From: Doug Anderson @ 2018-01-10 19:36 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1515569879-31808-2-git-send-email-wxt@rock-chips.com>
Hi,
On Tue, Jan 9, 2018 at 11:37 PM, Caesar Wang <wxt@rock-chips.com> wrote:
> From: Shawn Lin <shawn.lin@rock-chips.com>
>
> It turns out that 5us isn't enough for all cases, so let's
> retry some more times to wait for caldone.
>
> Signed-off-by: Shawn Lin <shawn.lin@rock-chips.com>
> Tested-by: Ziyuan Xu <xzy.xu@rock-chips.com>
> Signed-off-by: Caesar Wang <wxt@rock-chips.com>
> ---
>
> Changes in v2:
> - print the return valut with regmap_read_poll_timeout failing.
I agree with Brian that it was quite confusing to see a v2 from both
you and Shawn.
> drivers/phy/rockchip/phy-rockchip-emmc.c | 27 +++++++++++++++++----------
> 1 file changed, 17 insertions(+), 10 deletions(-)
>
> diff --git a/drivers/phy/rockchip/phy-rockchip-emmc.c b/drivers/phy/rockchip/phy-rockchip-emmc.c
> index f1b24f1..574838f 100644
> --- a/drivers/phy/rockchip/phy-rockchip-emmc.c
> +++ b/drivers/phy/rockchip/phy-rockchip-emmc.c
> @@ -76,6 +76,10 @@
> #define PHYCTRL_OTAPDLYSEL_MASK 0xf
> #define PHYCTRL_OTAPDLYSEL_SHIFT 0x7
>
> +#define PHYCTRL_IS_CALDONE(x) \
> + ((((x) >> PHYCTRL_CALDONE_SHIFT) & \
> + PHYCTRL_CALDONE_MASK) == PHYCTRL_CALDONE_DONE)
> +
> struct rockchip_emmc_phy {
> unsigned int reg_offset;
> struct regmap *reg_base;
> @@ -90,6 +94,7 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
> unsigned int freqsel = PHYCTRL_FREQSEL_200M;
> unsigned long rate;
> unsigned long timeout;
> + int ret;
>
> /*
> * Keep phyctrl_pdb and phyctrl_endll low to allow
> @@ -160,17 +165,19 @@ static int rockchip_emmc_phy_power(struct phy *phy, bool on_off)
> PHYCTRL_PDB_SHIFT));
>
> /*
> - * According to the user manual, it asks driver to
> - * wait 5us for calpad busy trimming
> + * According to the user manual, it asks driver to wait 5us for
> + * calpad busy trimming. However it is documented that this value is
> + * PVT(A.K.A process,voltage and temperature) relevant, so some
> + * failure cases are found which indicates we should be more tolerant
> + * to calpad busy trimming.
> */
> - udelay(5);
> - regmap_read(rk_phy->reg_base,
> - rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
> - &caldone);
> - caldone = (caldone >> PHYCTRL_CALDONE_SHIFT) & PHYCTRL_CALDONE_MASK;
> - if (caldone != PHYCTRL_CALDONE_DONE) {
> - pr_err("rockchip_emmc_phy_power: caldone timeout.\n");
> - return -ETIMEDOUT;
> + ret = regmap_read_poll_timeout(rk_phy->reg_base,
> + rk_phy->reg_offset + GRF_EMMCPHY_STATUS,
> + caldone, PHYCTRL_IS_CALDONE(caldone),
> + 5, 50);
>
> + if (ret) {
> + pr_err("%s: caldone timeout, ret=%d\n", __func__, ret);
In Shawn's v2, AKA <https://patchwork.kernel.org/patch/10154795/>,
this says "caldone failed", which I like better since not all failures
will be timeouts.
^ permalink raw reply
* [RFC PATCH] drivers: soc: xilinx: Add ZynqMP power domain driver
From: Jolly Shah @ 2018-01-10 19:58 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CAOFm3uFGuhBzXRrnuaFbdmjXSfq8Gm+Of93e3ovzdTZN1YaF9g@mail.gmail.com>
Thanks Philippe for review,
> -----Original Message-----
> From: Philippe Ombredanne [mailto:pombredanne at nexb.com]
> Sent: Tuesday, January 09, 2018 4:48 AM
> To: Jolly Shah <JOLLYS@xilinx.com>
> Cc: Matthias Brugger <matthias.bgg@gmail.com>; Andy Gross
> <andy.gross@linaro.org>; Shawn Guo <shawnguo@kernel.org>;
> geert+renesas at glider.be; Bjorn Andersson <bjorn.andersson@linaro.org>; Sean
> Wang <sean.wang@mediatek.com>; Marek Szyprowski
> <m.szyprowski@samsung.com>; Michal Simek <michal.simek@xilinx.com>;
> moderated list:ARM/FREESCALE IMX / MXC ARM ARCHITECTURE <linux-arm-
> kernel at lists.infradead.org>; LKML <linux-kernel@vger.kernel.org>; Jolly Shah
> <JOLLYS@xilinx.com>; Rajan Vaja <RAJANV@xilinx.com>
> Subject: Re: [RFC PATCH] drivers: soc: xilinx: Add ZynqMP power domain driver
>
> Jolly,
>
> On Mon, Jan 8, 2018 at 11:12 PM, Jolly Shah <jolly.shah@xilinx.com> wrote:
> > The zynqmp-genpd driver communicates the usage requirements for
> > logical power domains / devices to the platform FW.
> > FW is responsible for choosing appropriate power states, taking Linux'
> > usage information into account.
> >
> > Signed-off-by: Jolly Shah <jollys@xilinx.com>
> > Signed-off-by: Rajan Vaja <rajanv@xilinx.com>
> > ---
>
> <snip>
>
> > --- /dev/null
> > +++ b/drivers/soc/xilinx/zynqmp/pm_domains.c
> > @@ -0,0 +1,343 @@
> > +/*
> > + * ZynqMP Generic PM domain support
> > + *
> > + * Copyright (C) 2014-2017 Xilinx, Inc.
> > + *
> > + * Davorin Mista <davorin.mista@aggios.com>
> > + * Jolly Shah <jollys@xilinx.com>
> > + * Rajan Vaja <rajanv@xilinx.com>
> > + *
> > + * SPDX-License-Identifier: GPL-2.0+
> > + */
>
> This tag should be on the fist line as this:
>
> // SPDX-License-Identifier: GPL-2.0+
>
> --
> Cordially
> Philippe Ombredanne
Will fix it in next version
^ permalink raw reply
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