* [PULL 08/50] KVM: arm/arm64: Get rid of exported aliases to static functions
From: Christoffer Dall @ 2016-09-27 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160927180558.14699-1-christoffer.dall@linaro.org>
When rewriting the assembly code to C code, it was useful to have
exported aliases or static functions so that we could keep the existing
common C code unmodified and at the same time rewrite arm64 from
assembly to C code, and later do the arm part.
Now when both are done, we really don't need this level of indirection
anymore, and it's time to save a few lines and brain cells.
Acked-by: Marc Zyngier <marc.zyngier@arm.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
arch/arm/kvm/hyp/switch.c | 4 +---
arch/arm/kvm/hyp/tlb.c | 15 ++++-----------
arch/arm64/kvm/hyp/debug-sr.c | 4 +---
arch/arm64/kvm/hyp/switch.c | 4 +---
arch/arm64/kvm/hyp/tlb.c | 13 +++----------
arch/arm64/kvm/hyp/vgic-v3-sr.c | 4 +---
6 files changed, 11 insertions(+), 33 deletions(-)
diff --git a/arch/arm/kvm/hyp/switch.c b/arch/arm/kvm/hyp/switch.c
index b13caa9..37b3365 100644
--- a/arch/arm/kvm/hyp/switch.c
+++ b/arch/arm/kvm/hyp/switch.c
@@ -134,7 +134,7 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
return true;
}
-static int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
+int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
{
struct kvm_cpu_context *host_ctxt;
struct kvm_cpu_context *guest_ctxt;
@@ -191,8 +191,6 @@ again:
return exit_code;
}
-__alias(__guest_run) int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
-
static const char * const __hyp_panic_string[] = {
[ARM_EXCEPTION_RESET] = "\nHYP panic: RST PC:%08x CPSR:%08x",
[ARM_EXCEPTION_UNDEFINED] = "\nHYP panic: UNDEF PC:%08x CPSR:%08x",
diff --git a/arch/arm/kvm/hyp/tlb.c b/arch/arm/kvm/hyp/tlb.c
index a263600..7296528 100644
--- a/arch/arm/kvm/hyp/tlb.c
+++ b/arch/arm/kvm/hyp/tlb.c
@@ -34,7 +34,7 @@
* As v7 does not support flushing per IPA, just nuke the whole TLB
* instead, ignoring the ipa value.
*/
-static void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
+void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
{
dsb(ishst);
@@ -50,21 +50,14 @@ static void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
write_sysreg(0, VTTBR);
}
-__alias(__tlb_flush_vmid) void __kvm_tlb_flush_vmid(struct kvm *kvm);
-
-static void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
+void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
{
- __tlb_flush_vmid(kvm);
+ __kvm_tlb_flush_vmid(kvm);
}
-__alias(__tlb_flush_vmid_ipa) void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm,
- phys_addr_t ipa);
-
-static void __hyp_text __tlb_flush_vm_context(void)
+void __hyp_text __kvm_flush_vm_context(void)
{
write_sysreg(0, TLBIALLNSNHIS);
write_sysreg(0, ICIALLUIS);
dsb(ish);
}
-
-__alias(__tlb_flush_vm_context) void __kvm_flush_vm_context(void);
diff --git a/arch/arm64/kvm/hyp/debug-sr.c b/arch/arm64/kvm/hyp/debug-sr.c
index 33342a7..4ba5c90 100644
--- a/arch/arm64/kvm/hyp/debug-sr.c
+++ b/arch/arm64/kvm/hyp/debug-sr.c
@@ -131,9 +131,7 @@ void __hyp_text __debug_cond_restore_host_state(struct kvm_vcpu *vcpu)
vcpu->arch.debug_flags &= ~KVM_ARM64_DEBUG_DIRTY;
}
-static u32 __hyp_text __debug_read_mdcr_el2(void)
+u32 __hyp_text __kvm_get_mdcr_el2(void)
{
return read_sysreg(mdcr_el2);
}
-
-__alias(__debug_read_mdcr_el2) u32 __kvm_get_mdcr_el2(void);
diff --git a/arch/arm64/kvm/hyp/switch.c b/arch/arm64/kvm/hyp/switch.c
index 5a84b45..35d2e09 100644
--- a/arch/arm64/kvm/hyp/switch.c
+++ b/arch/arm64/kvm/hyp/switch.c
@@ -232,7 +232,7 @@ static bool __hyp_text __populate_fault_info(struct kvm_vcpu *vcpu)
return true;
}
-static int __hyp_text __guest_run(struct kvm_vcpu *vcpu)
+int __hyp_text __kvm_vcpu_run(struct kvm_vcpu *vcpu)
{
struct kvm_cpu_context *host_ctxt;
struct kvm_cpu_context *guest_ctxt;
@@ -293,8 +293,6 @@ again:
return exit_code;
}
-__alias(__guest_run) int __kvm_vcpu_run(struct kvm_vcpu *vcpu);
-
static const char __hyp_panic_string[] = "HYP panic:\nPS:%08llx PC:%016llx ESR:%08llx\nFAR:%016llx HPFAR:%016llx PAR:%016llx\nVCPU:%p\n";
static void __hyp_text __hyp_call_panic_nvhe(u64 spsr, u64 elr, u64 par)
diff --git a/arch/arm64/kvm/hyp/tlb.c b/arch/arm64/kvm/hyp/tlb.c
index be8177c..9cc0ea7 100644
--- a/arch/arm64/kvm/hyp/tlb.c
+++ b/arch/arm64/kvm/hyp/tlb.c
@@ -17,7 +17,7 @@
#include <asm/kvm_hyp.h>
-static void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
+void __hyp_text __kvm_tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
{
dsb(ishst);
@@ -48,10 +48,7 @@ static void __hyp_text __tlb_flush_vmid_ipa(struct kvm *kvm, phys_addr_t ipa)
write_sysreg(0, vttbr_el2);
}
-__alias(__tlb_flush_vmid_ipa) void __kvm_tlb_flush_vmid_ipa(struct kvm *kvm,
- phys_addr_t ipa);
-
-static void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
+void __hyp_text __kvm_tlb_flush_vmid(struct kvm *kvm)
{
dsb(ishst);
@@ -67,14 +64,10 @@ static void __hyp_text __tlb_flush_vmid(struct kvm *kvm)
write_sysreg(0, vttbr_el2);
}
-__alias(__tlb_flush_vmid) void __kvm_tlb_flush_vmid(struct kvm *kvm);
-
-static void __hyp_text __tlb_flush_vm_context(void)
+void __hyp_text __kvm_flush_vm_context(void)
{
dsb(ishst);
asm volatile("tlbi alle1is \n"
"ic ialluis ": : );
dsb(ish);
}
-
-__alias(__tlb_flush_vm_context) void __kvm_flush_vm_context(void);
diff --git a/arch/arm64/kvm/hyp/vgic-v3-sr.c b/arch/arm64/kvm/hyp/vgic-v3-sr.c
index 5f8f80b..ee1ea63 100644
--- a/arch/arm64/kvm/hyp/vgic-v3-sr.c
+++ b/arch/arm64/kvm/hyp/vgic-v3-sr.c
@@ -335,9 +335,7 @@ void __hyp_text __vgic_v3_init_lrs(void)
__gic_v3_set_lr(0, i);
}
-static u64 __hyp_text __vgic_v3_read_ich_vtr_el2(void)
+u64 __hyp_text __vgic_v3_get_ich_vtr_el2(void)
{
return read_gicreg(ICH_VTR_EL2);
}
-
-__alias(__vgic_v3_read_ich_vtr_el2) u64 __vgic_v3_get_ich_vtr_el2(void);
--
2.9.0
^ permalink raw reply related
* [PULL 07/50] arm64/kvm: remove unused stub functions
From: Christoffer Dall @ 2016-09-27 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160927180558.14699-1-christoffer.dall@linaro.org>
From: Mark Rutland <mark.rutland@arm.com>
Now that 32-bit KVM no longer performs cache maintenance for page table
updates, we no longer need empty stubs for arm64. Remove them.
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: kvmarm at lists.cs.columbia.edu
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
arch/arm64/include/asm/kvm_mmu.h | 6 ------
1 file changed, 6 deletions(-)
diff --git a/arch/arm64/include/asm/kvm_mmu.h b/arch/arm64/include/asm/kvm_mmu.h
index b6bb834..8f99ab6 100644
--- a/arch/arm64/include/asm/kvm_mmu.h
+++ b/arch/arm64/include/asm/kvm_mmu.h
@@ -166,12 +166,6 @@ 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)
-static inline void kvm_clean_pgd(pgd_t *pgd) {}
-static inline void kvm_clean_pmd(pmd_t *pmd) {}
-static inline void kvm_clean_pmd_entry(pmd_t *pmd) {}
-static inline void kvm_clean_pte(pte_t *pte) {}
-static inline void kvm_clean_pte_entry(pte_t *pte) {}
-
static inline pte_t kvm_s2pte_mkwrite(pte_t pte)
{
pte_val(pte) |= PTE_S2_RDWR;
--
2.9.0
^ permalink raw reply related
* [PULL 06/50] arm/kvm: excise redundant cache maintenance
From: Christoffer Dall @ 2016-09-27 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160927180558.14699-1-christoffer.dall@linaro.org>
From: Mark Rutland <mark.rutland@arm.com>
When modifying Stage-2 page tables, we perform cache maintenance to
account for non-coherent page table walks. However, this is unnecessary,
as page table walks are guaranteed to be coherent in the presence of the
virtualization extensions.
Per ARM DDI 0406C.c, section B1.7 ("The Virtualization Extensions"), the
virtualization extensions mandate the multiprocessing extensions.
Per ARM DDI 0406C.c, section B3.10.1 ("General TLB maintenance
requirements"), as described in the sub-section titled "TLB maintenance
operations and the memory order model", this maintenance is not required
in the presence of the multiprocessing extensions.
Hence, we need not perform this cache maintenance when modifying Stage-2
entries.
This patch removes the logic for performing the redundant maintenance.
To ensure visibility and ordering of updates, a dsb(ishst) that was
otherwise implicit in the maintenance is folded into kvm_set_pmd() and
kvm_set_pte().
Signed-off-by: Mark Rutland <mark.rutland@arm.com>
Cc: Christoffer Dall <christoffer.dall@linaro.org>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Cc: kvmarm at lists.cs.columbia.edu
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
arch/arm/include/asm/kvm_mmu.h | 28 ++--------------------------
arch/arm/kvm/mmu.c | 2 --
2 files changed, 2 insertions(+), 28 deletions(-)
diff --git a/arch/arm/include/asm/kvm_mmu.h b/arch/arm/include/asm/kvm_mmu.h
index 3bb803d..74a44727 100644
--- a/arch/arm/include/asm/kvm_mmu.h
+++ b/arch/arm/include/asm/kvm_mmu.h
@@ -63,37 +63,13 @@ void kvm_clear_hyp_idmap(void);
static inline void kvm_set_pmd(pmd_t *pmd, pmd_t new_pmd)
{
*pmd = new_pmd;
- flush_pmd_entry(pmd);
+ dsb(ishst);
}
static inline void kvm_set_pte(pte_t *pte, pte_t new_pte)
{
*pte = new_pte;
- /*
- * flush_pmd_entry just takes a void pointer and cleans the necessary
- * cache entries, so we can reuse the function for ptes.
- */
- flush_pmd_entry(pte);
-}
-
-static inline void kvm_clean_pgd(pgd_t *pgd)
-{
- clean_dcache_area(pgd, PTRS_PER_S2_PGD * sizeof(pgd_t));
-}
-
-static inline void kvm_clean_pmd(pmd_t *pmd)
-{
- clean_dcache_area(pmd, PTRS_PER_PMD * sizeof(pmd_t));
-}
-
-static inline void kvm_clean_pmd_entry(pmd_t *pmd)
-{
- clean_pmd_entry(pmd);
-}
-
-static inline void kvm_clean_pte(pte_t *pte)
-{
- clean_pte_table(pte);
+ dsb(ishst);
}
static inline pte_t kvm_s2pte_mkwrite(pte_t pte)
diff --git a/arch/arm/kvm/mmu.c b/arch/arm/kvm/mmu.c
index 29d0b23..344755d 100644
--- a/arch/arm/kvm/mmu.c
+++ b/arch/arm/kvm/mmu.c
@@ -744,7 +744,6 @@ int kvm_alloc_stage2_pgd(struct kvm *kvm)
if (!pgd)
return -ENOMEM;
- kvm_clean_pgd(pgd);
kvm->arch.pgd = pgd;
return 0;
}
@@ -936,7 +935,6 @@ static int stage2_set_pte(struct kvm *kvm, struct kvm_mmu_memory_cache *cache,
if (!cache)
return 0; /* ignore calls from kvm_set_spte_hva */
pte = mmu_memory_cache_alloc(cache);
- kvm_clean_pte(pte);
pmd_populate_kernel(NULL, pmd, pte);
get_page(virt_to_page(pmd));
}
--
2.9.0
^ permalink raw reply related
* [PULL 05/50] KVM: arm: vgic: Drop build compatibility hack for older kernel versions
From: Christoffer Dall @ 2016-09-27 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160927180558.14699-1-christoffer.dall@linaro.org>
From: Marc Zyngier <marc.zyngier@arm.com>
As kvm_set_routing_entry() was changing prototype between 4.7 and 4.8,
an ugly hack was put in place in order to survive both building in
-next and the merge window.
Now that everything has been merged, let's dump the compatibility
hack for good.
Signed-off-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
virt/kvm/arm/vgic/vgic-irqfd.c | 6 ------
1 file changed, 6 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-irqfd.c b/virt/kvm/arm/vgic/vgic-irqfd.c
index b31a51a..d918dcf 100644
--- a/virt/kvm/arm/vgic/vgic-irqfd.c
+++ b/virt/kvm/arm/vgic/vgic-irqfd.c
@@ -46,15 +46,9 @@ static int vgic_irqfd_set_irq(struct kvm_kernel_irq_routing_entry *e,
* @ue: user api routing entry handle
* return 0 on success, -EINVAL on errors.
*/
-#ifdef KVM_CAP_X2APIC_API
int kvm_set_routing_entry(struct kvm *kvm,
struct kvm_kernel_irq_routing_entry *e,
const struct kvm_irq_routing_entry *ue)
-#else
-/* Remove this version and the ifdefery once merged into 4.8 */
-int kvm_set_routing_entry(struct kvm_kernel_irq_routing_entry *e,
- const struct kvm_irq_routing_entry *ue)
-#endif
{
int r = -EINVAL;
--
2.9.0
^ permalink raw reply related
* [PULL 04/50] arm64: KVM: Optimize __guest_enter/exit() to save a few instructions
From: Christoffer Dall @ 2016-09-27 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160927180558.14699-1-christoffer.dall@linaro.org>
From: Shanker Donthineni <shankerd@codeaurora.org>
We are doing an unnecessary stack push/pop operation when restoring
the guest registers x0-x18 in __guest_enter(). This patch saves the
two instructions by using x18 as a base register. No need to store
the vcpu context pointer in stack because it is redundant, the same
information is available in tpidr_el2. The function __guest_exit()
calling convention is slightly modified, caller only pushes the regs
x0-x1 to stack instead of regs x0-x3.
Signed-off-by: Shanker Donthineni <shankerd@codeaurora.org>
Reviewed-by: Christoffer Dall <christoffer.dall@linaro.org>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
arch/arm64/kvm/hyp/entry.S | 101 ++++++++++++++++++++---------------------
arch/arm64/kvm/hyp/hyp-entry.S | 37 ++++++---------
2 files changed, 63 insertions(+), 75 deletions(-)
diff --git a/arch/arm64/kvm/hyp/entry.S b/arch/arm64/kvm/hyp/entry.S
index ce9e5e5..3967c231 100644
--- a/arch/arm64/kvm/hyp/entry.S
+++ b/arch/arm64/kvm/hyp/entry.S
@@ -55,79 +55,78 @@
*/
ENTRY(__guest_enter)
// x0: vcpu
- // x1: host/guest context
- // x2-x18: clobbered by macros
+ // x1: host context
+ // x2-x17: clobbered by macros
+ // x18: guest context
// Store the host regs
save_callee_saved_regs x1
- // Preserve vcpu & host_ctxt for use at exit time
- stp x0, x1, [sp, #-16]!
+ // Store the host_ctxt for use at exit time
+ str x1, [sp, #-16]!
- add x1, x0, #VCPU_CONTEXT
+ add x18, x0, #VCPU_CONTEXT
- // Prepare x0-x1 for later restore by pushing them onto the stack
- ldp x2, x3, [x1, #CPU_XREG_OFFSET(0)]
- stp x2, x3, [sp, #-16]!
+ // Restore guest regs x0-x17
+ ldp x0, x1, [x18, #CPU_XREG_OFFSET(0)]
+ ldp x2, x3, [x18, #CPU_XREG_OFFSET(2)]
+ ldp x4, x5, [x18, #CPU_XREG_OFFSET(4)]
+ ldp x6, x7, [x18, #CPU_XREG_OFFSET(6)]
+ ldp x8, x9, [x18, #CPU_XREG_OFFSET(8)]
+ ldp x10, x11, [x18, #CPU_XREG_OFFSET(10)]
+ ldp x12, x13, [x18, #CPU_XREG_OFFSET(12)]
+ ldp x14, x15, [x18, #CPU_XREG_OFFSET(14)]
+ ldp x16, x17, [x18, #CPU_XREG_OFFSET(16)]
- // x2-x18
- ldp x2, x3, [x1, #CPU_XREG_OFFSET(2)]
- ldp x4, x5, [x1, #CPU_XREG_OFFSET(4)]
- ldp x6, x7, [x1, #CPU_XREG_OFFSET(6)]
- ldp x8, x9, [x1, #CPU_XREG_OFFSET(8)]
- ldp x10, x11, [x1, #CPU_XREG_OFFSET(10)]
- ldp x12, x13, [x1, #CPU_XREG_OFFSET(12)]
- ldp x14, x15, [x1, #CPU_XREG_OFFSET(14)]
- ldp x16, x17, [x1, #CPU_XREG_OFFSET(16)]
- ldr x18, [x1, #CPU_XREG_OFFSET(18)]
-
- // x19-x29, lr
- restore_callee_saved_regs x1
-
- // Last bits of the 64bit state
- ldp x0, x1, [sp], #16
+ // Restore guest regs x19-x29, lr
+ restore_callee_saved_regs x18
+
+ // Restore guest reg x18
+ ldr x18, [x18, #CPU_XREG_OFFSET(18)]
// Do not touch any register after this!
eret
ENDPROC(__guest_enter)
ENTRY(__guest_exit)
- // x0: vcpu
- // x1: return code
- // x2-x3: free
- // x4-x29,lr: vcpu regs
- // vcpu x0-x3 on the stack
-
- add x2, x0, #VCPU_CONTEXT
-
- stp x4, x5, [x2, #CPU_XREG_OFFSET(4)]
- stp x6, x7, [x2, #CPU_XREG_OFFSET(6)]
- stp x8, x9, [x2, #CPU_XREG_OFFSET(8)]
- stp x10, x11, [x2, #CPU_XREG_OFFSET(10)]
- stp x12, x13, [x2, #CPU_XREG_OFFSET(12)]
- stp x14, x15, [x2, #CPU_XREG_OFFSET(14)]
- stp x16, x17, [x2, #CPU_XREG_OFFSET(16)]
- str x18, [x2, #CPU_XREG_OFFSET(18)]
-
- ldp x6, x7, [sp], #16 // x2, x3
- ldp x4, x5, [sp], #16 // x0, x1
-
- stp x4, x5, [x2, #CPU_XREG_OFFSET(0)]
- stp x6, x7, [x2, #CPU_XREG_OFFSET(2)]
+ // x0: return code
+ // x1: vcpu
+ // x2-x29,lr: vcpu regs
+ // vcpu x0-x1 on the stack
+
+ add x1, x1, #VCPU_CONTEXT
+
+ // Store the guest regs x2 and x3
+ stp x2, x3, [x1, #CPU_XREG_OFFSET(2)]
+
+ // Retrieve the guest regs x0-x1 from the stack
+ ldp x2, x3, [sp], #16 // x0, x1
+
+ // Store the guest regs x0-x1 and x4-x18
+ stp x2, x3, [x1, #CPU_XREG_OFFSET(0)]
+ stp x4, x5, [x1, #CPU_XREG_OFFSET(4)]
+ stp x6, x7, [x1, #CPU_XREG_OFFSET(6)]
+ stp x8, x9, [x1, #CPU_XREG_OFFSET(8)]
+ stp x10, x11, [x1, #CPU_XREG_OFFSET(10)]
+ stp x12, x13, [x1, #CPU_XREG_OFFSET(12)]
+ stp x14, x15, [x1, #CPU_XREG_OFFSET(14)]
+ stp x16, x17, [x1, #CPU_XREG_OFFSET(16)]
+ str x18, [x1, #CPU_XREG_OFFSET(18)]
+
+ // Store the guest regs x19-x29, lr
+ save_callee_saved_regs x1
- save_callee_saved_regs x2
+ // Restore the host_ctxt from the stack
+ ldr x2, [sp], #16
- // Restore vcpu & host_ctxt from the stack
- // (preserving return code in x1)
- ldp x0, x2, [sp], #16
// Now restore the host regs
restore_callee_saved_regs x2
- mov x0, x1
ret
ENDPROC(__guest_exit)
ENTRY(__fpsimd_guest_restore)
+ stp x2, x3, [sp, #-16]!
stp x4, lr, [sp, #-16]!
alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
diff --git a/arch/arm64/kvm/hyp/hyp-entry.S b/arch/arm64/kvm/hyp/hyp-entry.S
index f6d9694..d6cae54 100644
--- a/arch/arm64/kvm/hyp/hyp-entry.S
+++ b/arch/arm64/kvm/hyp/hyp-entry.S
@@ -27,16 +27,6 @@
.text
.pushsection .hyp.text, "ax"
-.macro save_x0_to_x3
- stp x0, x1, [sp, #-16]!
- stp x2, x3, [sp, #-16]!
-.endm
-
-.macro restore_x0_to_x3
- ldp x2, x3, [sp], #16
- ldp x0, x1, [sp], #16
-.endm
-
.macro do_el2_call
/*
* Shuffle the parameters before calling the function
@@ -79,23 +69,23 @@ ENTRY(__kvm_hyp_teardown)
ENDPROC(__kvm_hyp_teardown)
el1_sync: // Guest trapped into EL2
- save_x0_to_x3
+ stp x0, x1, [sp, #-16]!
alternative_if_not ARM64_HAS_VIRT_HOST_EXTN
mrs x1, esr_el2
alternative_else
mrs x1, esr_el1
alternative_endif
- lsr x2, x1, #ESR_ELx_EC_SHIFT
+ lsr x0, x1, #ESR_ELx_EC_SHIFT
- cmp x2, #ESR_ELx_EC_HVC64
+ cmp x0, #ESR_ELx_EC_HVC64
b.ne el1_trap
- mrs x3, vttbr_el2 // If vttbr is valid, the 64bit guest
- cbnz x3, el1_trap // called HVC
+ mrs x1, vttbr_el2 // If vttbr is valid, the 64bit guest
+ cbnz x1, el1_trap // called HVC
/* Here, we're pretty sure the host called HVC. */
- restore_x0_to_x3
+ ldp x0, x1, [sp], #16
cmp x0, #HVC_GET_VECTORS
b.ne 1f
@@ -113,22 +103,21 @@ alternative_endif
el1_trap:
/*
- * x1: ESR
- * x2: ESR_EC
+ * x0: ESR_EC
*/
/* Guest accessed VFP/SIMD registers, save host, restore Guest */
- cmp x2, #ESR_ELx_EC_FP_ASIMD
+ cmp x0, #ESR_ELx_EC_FP_ASIMD
b.eq __fpsimd_guest_restore
- mrs x0, tpidr_el2
- mov x1, #ARM_EXCEPTION_TRAP
+ mrs x1, tpidr_el2
+ mov x0, #ARM_EXCEPTION_TRAP
b __guest_exit
el1_irq:
- save_x0_to_x3
- mrs x0, tpidr_el2
- mov x1, #ARM_EXCEPTION_IRQ
+ stp x0, x1, [sp, #-16]!
+ mrs x1, tpidr_el2
+ mov x0, #ARM_EXCEPTION_IRQ
b __guest_exit
ENTRY(__hyp_do_panic)
--
2.9.0
^ permalink raw reply related
* [PULL 03/50] KVM: arm/arm64: Rename vgic_attr_regs_access to vgic_attr_regs_access_v2
From: Christoffer Dall @ 2016-09-27 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160927180558.14699-1-christoffer.dall@linaro.org>
Just a rename so we can implement a v3-specific function later.
We take the chance to get rid of the V2/V3 ops comments as well.
No functional change.
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
virt/kvm/arm/vgic/vgic-kvm-device.c | 26 +++++++++++---------------
1 file changed, 11 insertions(+), 15 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 19fa331..163b057 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -294,17 +294,17 @@ static bool lock_all_vcpus(struct kvm *kvm)
return true;
}
-/** vgic_attr_regs_access: allows user space to read/write VGIC registers
- *
- * @dev: kvm device handle
- * @attr: kvm device attribute
- * @reg: address the value is read or written
- * @is_write: write flag
+/**
+ * vgic_attr_regs_access_v2 - allows user space to access VGIC v2 state
*
+ * @dev: kvm device handle
+ * @attr: kvm device attribute
+ * @reg: address the value is read or written
+ * @is_write: true if userspace is writing a register
*/
-static int vgic_attr_regs_access(struct kvm_device *dev,
- struct kvm_device_attr *attr,
- u32 *reg, bool is_write)
+static int vgic_attr_regs_access_v2(struct kvm_device *dev,
+ struct kvm_device_attr *attr,
+ u32 *reg, bool is_write)
{
struct vgic_reg_attr reg_attr;
gpa_t addr;
@@ -347,8 +347,6 @@ out:
return ret;
}
-/* V2 ops */
-
static int vgic_v2_set_attr(struct kvm_device *dev,
struct kvm_device_attr *attr)
{
@@ -367,7 +365,7 @@ static int vgic_v2_set_attr(struct kvm_device *dev,
if (get_user(reg, uaddr))
return -EFAULT;
- return vgic_attr_regs_access(dev, attr, ®, true);
+ return vgic_attr_regs_access_v2(dev, attr, ®, true);
}
}
@@ -389,7 +387,7 @@ static int vgic_v2_get_attr(struct kvm_device *dev,
u32 __user *uaddr = (u32 __user *)(long)attr->addr;
u32 reg = 0;
- ret = vgic_attr_regs_access(dev, attr, ®, false);
+ ret = vgic_attr_regs_access_v2(dev, attr, ®, false);
if (ret)
return ret;
return put_user(reg, uaddr);
@@ -433,8 +431,6 @@ struct kvm_device_ops kvm_arm_vgic_v2_ops = {
.has_attr = vgic_v2_has_attr,
};
-/* V3 ops */
-
#ifdef CONFIG_KVM_ARM_VGIC_V3
static int vgic_v3_set_attr(struct kvm_device *dev,
--
2.9.0
^ permalink raw reply related
* [PULL 02/50] KVM: arm/arm64: Factor out vgic_attr_regs_access functionality
From: Christoffer Dall @ 2016-09-27 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160927180558.14699-1-christoffer.dall@linaro.org>
As we are about to deal with multiple data types and situations where
the vgic should not be initialized when doing userspace accesses on the
register attributes, factor out the functionality of
vgic_attr_regs_access into smaller bits which can be reused by a new
function later.
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
Reviewed-by: Eric Auger <eric.auger@redhat.com>
---
virt/kvm/arm/vgic/vgic-kvm-device.c | 100 ++++++++++++++++++++++++++----------
1 file changed, 73 insertions(+), 27 deletions(-)
diff --git a/virt/kvm/arm/vgic/vgic-kvm-device.c b/virt/kvm/arm/vgic/vgic-kvm-device.c
index 1813f93..19fa331 100644
--- a/virt/kvm/arm/vgic/vgic-kvm-device.c
+++ b/virt/kvm/arm/vgic/vgic-kvm-device.c
@@ -233,6 +233,67 @@ int kvm_register_vgic_device(unsigned long type)
return ret;
}
+struct vgic_reg_attr {
+ struct kvm_vcpu *vcpu;
+ gpa_t addr;
+};
+
+static int parse_vgic_v2_attr(struct kvm_device *dev,
+ struct kvm_device_attr *attr,
+ struct vgic_reg_attr *reg_attr)
+{
+ int cpuid;
+
+ cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
+ KVM_DEV_ARM_VGIC_CPUID_SHIFT;
+
+ if (cpuid >= atomic_read(&dev->kvm->online_vcpus))
+ return -EINVAL;
+
+ reg_attr->vcpu = kvm_get_vcpu(dev->kvm, cpuid);
+ reg_attr->addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+
+ return 0;
+}
+
+/* unlocks vcpus from @vcpu_lock_idx and smaller */
+static void unlock_vcpus(struct kvm *kvm, int vcpu_lock_idx)
+{
+ struct kvm_vcpu *tmp_vcpu;
+
+ for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
+ tmp_vcpu = kvm_get_vcpu(kvm, vcpu_lock_idx);
+ mutex_unlock(&tmp_vcpu->mutex);
+ }
+}
+
+static void unlock_all_vcpus(struct kvm *kvm)
+{
+ unlock_vcpus(kvm, atomic_read(&kvm->online_vcpus) - 1);
+}
+
+/* Returns true if all vcpus were locked, false otherwise */
+static bool lock_all_vcpus(struct kvm *kvm)
+{
+ struct kvm_vcpu *tmp_vcpu;
+ int c;
+
+ /*
+ * Any time a vcpu is run, vcpu_load is called which tries to grab the
+ * vcpu->mutex. By grabbing the vcpu->mutex of all VCPUs we ensure
+ * that no other VCPUs are run and fiddle with the vgic state while we
+ * access it.
+ */
+ kvm_for_each_vcpu(c, tmp_vcpu, kvm) {
+ if (!mutex_trylock(&tmp_vcpu->mutex)) {
+ unlock_vcpus(kvm, c - 1);
+ return false;
+ }
+ }
+
+ return true;
+}
+
/** vgic_attr_regs_access: allows user space to read/write VGIC registers
*
* @dev: kvm device handle
@@ -245,15 +306,17 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
struct kvm_device_attr *attr,
u32 *reg, bool is_write)
{
+ struct vgic_reg_attr reg_attr;
gpa_t addr;
- int cpuid, ret, c;
- struct kvm_vcpu *vcpu, *tmp_vcpu;
- int vcpu_lock_idx = -1;
+ struct kvm_vcpu *vcpu;
+ int ret;
- cpuid = (attr->attr & KVM_DEV_ARM_VGIC_CPUID_MASK) >>
- KVM_DEV_ARM_VGIC_CPUID_SHIFT;
- vcpu = kvm_get_vcpu(dev->kvm, cpuid);
- addr = attr->attr & KVM_DEV_ARM_VGIC_OFFSET_MASK;
+ ret = parse_vgic_v2_attr(dev, attr, ®_attr);
+ if (ret)
+ return ret;
+
+ vcpu = reg_attr.vcpu;
+ addr = reg_attr.addr;
mutex_lock(&dev->kvm->lock);
@@ -261,24 +324,11 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
if (ret)
goto out;
- if (cpuid >= atomic_read(&dev->kvm->online_vcpus)) {
- ret = -EINVAL;
+ if (!lock_all_vcpus(dev->kvm)) {
+ ret = -EBUSY;
goto out;
}
- /*
- * Any time a vcpu is run, vcpu_load is called which tries to grab the
- * vcpu->mutex. By grabbing the vcpu->mutex of all VCPUs we ensure
- * that no other VCPUs are run and fiddle with the vgic state while we
- * access it.
- */
- ret = -EBUSY;
- kvm_for_each_vcpu(c, tmp_vcpu, dev->kvm) {
- if (!mutex_trylock(&tmp_vcpu->mutex))
- goto out;
- vcpu_lock_idx = c;
- }
-
switch (attr->group) {
case KVM_DEV_ARM_VGIC_GRP_CPU_REGS:
ret = vgic_v2_cpuif_uaccess(vcpu, is_write, addr, reg);
@@ -291,12 +341,8 @@ static int vgic_attr_regs_access(struct kvm_device *dev,
break;
}
+ unlock_all_vcpus(dev->kvm);
out:
- for (; vcpu_lock_idx >= 0; vcpu_lock_idx--) {
- tmp_vcpu = kvm_get_vcpu(dev->kvm, vcpu_lock_idx);
- mutex_unlock(&tmp_vcpu->mutex);
- }
-
mutex_unlock(&dev->kvm->lock);
return ret;
}
--
2.9.0
^ permalink raw reply related
* [PULL 01/50] KVM: arm/arm64: Add VGICv3 save/restore API documentation
From: Christoffer Dall @ 2016-09-27 18:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160927180558.14699-1-christoffer.dall@linaro.org>
Factor out the GICv3 and ITS-specific documentation into a separate
documentation file. Add description for how to access distributor,
redistributor, and CPU interface registers for GICv3 in this new file,
and add a group for accessing level triggered IRQ information for GICv3
as well.
Reviewed-by: Marc Zyngier <marc.zyngier@arm.com>
Reviewed-by: Peter Maydell <peter.maydell@linaro.org>
Signed-off-by: Christoffer Dall <christoffer.dall@linaro.org>
---
Documentation/virtual/kvm/devices/arm-vgic-its.txt | 38 ++++
Documentation/virtual/kvm/devices/arm-vgic-v3.txt | 206 +++++++++++++++++++++
Documentation/virtual/kvm/devices/arm-vgic.txt | 52 ++----
3 files changed, 261 insertions(+), 35 deletions(-)
create mode 100644 Documentation/virtual/kvm/devices/arm-vgic-its.txt
create mode 100644 Documentation/virtual/kvm/devices/arm-vgic-v3.txt
diff --git a/Documentation/virtual/kvm/devices/arm-vgic-its.txt b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
new file mode 100644
index 0000000..6081a5b
--- /dev/null
+++ b/Documentation/virtual/kvm/devices/arm-vgic-its.txt
@@ -0,0 +1,38 @@
+ARM Virtual Interrupt Translation Service (ITS)
+===============================================
+
+Device types supported:
+ KVM_DEV_TYPE_ARM_VGIC_ITS ARM Interrupt Translation Service Controller
+
+The ITS allows MSI(-X) interrupts to be injected into guests. This extension is
+optional. Creating a virtual ITS controller also requires a host GICv3 (see
+arm-vgic-v3.txt), but does not depend on having physical ITS controllers.
+
+There can be multiple ITS controllers per guest, each of them has to have
+a separate, non-overlapping MMIO region.
+
+
+Groups:
+ KVM_DEV_ARM_VGIC_GRP_ADDR
+ Attributes:
+ KVM_VGIC_ITS_ADDR_TYPE (rw, 64-bit)
+ Base address in the guest physical address space of the GICv3 ITS
+ control register frame.
+ This address needs to be 64K aligned and the region covers 128K.
+ Errors:
+ -E2BIG: Address outside of addressable IPA range
+ -EINVAL: Incorrectly aligned address
+ -EEXIST: Address already configured
+ -EFAULT: Invalid user pointer for attr->addr.
+ -ENODEV: Incorrect attribute or the ITS is not supported.
+
+
+ KVM_DEV_ARM_VGIC_GRP_CTRL
+ Attributes:
+ KVM_DEV_ARM_VGIC_CTRL_INIT
+ request the initialization of the ITS, no additional parameter in
+ kvm_device_attr.addr.
+ Errors:
+ -ENXIO: ITS not properly configured as required prior to setting
+ this attribute
+ -ENOMEM: Memory shortage when allocating ITS internal data
diff --git a/Documentation/virtual/kvm/devices/arm-vgic-v3.txt b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
new file mode 100644
index 0000000..9348b3c
--- /dev/null
+++ b/Documentation/virtual/kvm/devices/arm-vgic-v3.txt
@@ -0,0 +1,206 @@
+ARM Virtual Generic Interrupt Controller v3 and later (VGICv3)
+==============================================================
+
+
+Device types supported:
+ KVM_DEV_TYPE_ARM_VGIC_V3 ARM Generic Interrupt Controller v3.0
+
+Only one VGIC instance may be instantiated through this API. The created VGIC
+will act as the VM interrupt controller, requiring emulated user-space devices
+to inject interrupts to the VGIC instead of directly to CPUs. It is not
+possible to create both a GICv3 and GICv2 on the same VM.
+
+Creating a guest GICv3 device requires a host GICv3 as well.
+
+
+Groups:
+ KVM_DEV_ARM_VGIC_GRP_ADDR
+ Attributes:
+ KVM_VGIC_V3_ADDR_TYPE_DIST (rw, 64-bit)
+ Base address in the guest physical address space of the GICv3 distributor
+ register mappings. Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
+ This address needs to be 64K aligned and the region covers 64 KByte.
+
+ KVM_VGIC_V3_ADDR_TYPE_REDIST (rw, 64-bit)
+ Base address in the guest physical address space of the GICv3
+ redistributor register mappings. There are two 64K pages for each
+ VCPU and all of the redistributor pages are contiguous.
+ Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
+ This address needs to be 64K aligned.
+ Errors:
+ -E2BIG: Address outside of addressable IPA range
+ -EINVAL: Incorrectly aligned address
+ -EEXIST: Address already configured
+ -ENXIO: The group or attribute is unknown/unsupported for this device
+ or hardware support is missing.
+ -EFAULT: Invalid user pointer for attr->addr.
+
+
+
+ KVM_DEV_ARM_VGIC_GRP_DIST_REGS
+ KVM_DEV_ARM_VGIC_GRP_REDIST_REGS
+ Attributes:
+ The attr field of kvm_device_attr encodes two values:
+ bits: | 63 .... 32 | 31 .... 0 |
+ values: | mpidr | offset |
+
+ All distributor regs are (rw, 32-bit) and kvm_device_attr.addr points to a
+ __u32 value. 64-bit registers must be accessed by separately accessing the
+ lower and higher word.
+
+ Writes to read-only registers are ignored by the kernel.
+
+ KVM_DEV_ARM_VGIC_GRP_DIST_REGS accesses the main distributor registers.
+ KVM_DEV_ARM_VGIC_GRP_REDIST_REGS accesses the redistributor of the CPU
+ specified by the mpidr.
+
+ The offset is relative to the "[Re]Distributor base address" as defined
+ in the GICv3/4 specs. Getting or setting such a register has the same
+ effect as reading or writing the register on real hardware, except for the
+ following registers: GICD_STATUSR, GICR_STATUSR, GICD_ISPENDR,
+ GICR_ISPENDR0, GICD_ICPENDR, and GICR_ICPENDR0. These registers behave
+ differently when accessed via this interface compared to their
+ architecturally defined behavior to allow software a full view of the
+ VGIC's internal state.
+
+ The mpidr field is used to specify which
+ redistributor is accessed. The mpidr is ignored for the distributor.
+
+ The mpidr encoding is based on the affinity information in the
+ architecture defined MPIDR, and the field is encoded as follows:
+ | 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 |
+ | Aff3 | Aff2 | Aff1 | Aff0 |
+
+ Note that distributor fields are not banked, but return the same value
+ regardless of the mpidr used to access the register.
+
+ The GICD_STATUSR and GICR_STATUSR registers are architecturally defined such
+ that a write of a clear bit has no effect, whereas a write with a set bit
+ clears that value. To allow userspace to freely set the values of these two
+ registers, setting the attributes with the register offsets for these two
+ registers simply sets the non-reserved bits to the value written.
+
+
+ Accesses (reads and writes) to the GICD_ISPENDR register region and
+ GICR_ISPENDR0 registers get/set the value of the latched pending state for
+ the interrupts.
+
+ This is identical to the value returned by a guest read from ISPENDR for an
+ edge triggered interrupt, but may differ for level triggered interrupts.
+ For edge triggered interrupts, once an interrupt becomes pending (whether
+ because of an edge detected on the input line or because of a guest write
+ to ISPENDR) this state is "latched", and only cleared when either the
+ interrupt is activated or when the guest writes to ICPENDR. A level
+ triggered interrupt may be pending either because the level input is held
+ high by a device, or because of a guest write to the ISPENDR register. Only
+ ISPENDR writes are latched; if the device lowers the line level then the
+ interrupt is no longer pending unless the guest also wrote to ISPENDR, and
+ conversely writes to ICPENDR or activations of the interrupt do not clear
+ the pending status if the line level is still being held high. (These
+ rules are documented in the GICv3 specification descriptions of the ICPENDR
+ and ISPENDR registers.) For a level triggered interrupt the value accessed
+ here is that of the latch which is set by ISPENDR and cleared by ICPENDR or
+ interrupt activation, whereas the value returned by a guest read from
+ ISPENDR is the logical OR of the latch value and the input line level.
+
+ Raw access to the latch state is provided to userspace so that it can save
+ and restore the entire GIC internal state (which is defined by the
+ combination of the current input line level and the latch state, and cannot
+ be deduced from purely the line level and the value of the ISPENDR
+ registers).
+
+ Accesses to GICD_ICPENDR register region and GICR_ICPENDR0 registers have
+ RAZ/WI semantics, meaning that reads always return 0 and writes are always
+ ignored.
+
+ Errors:
+ -ENXIO: Getting or setting this register is not yet supported
+ -EBUSY: One or more VCPUs are running
+
+
+ KVM_DEV_ARM_VGIC_CPU_SYSREGS
+ Attributes:
+ The attr field of kvm_device_attr encodes two values:
+ bits: | 63 .... 32 | 31 .... 16 | 15 .... 0 |
+ values: | mpidr | RES | instr |
+
+ The mpidr field encodes the CPU ID based on the affinity information in the
+ architecture defined MPIDR, and the field is encoded as follows:
+ | 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 |
+ | Aff3 | Aff2 | Aff1 | Aff0 |
+
+ The instr field encodes the system register to access based on the fields
+ defined in the A64 instruction set encoding for system register access
+ (RES means the bits are reserved for future use and should be zero):
+
+ | 15 ... 14 | 13 ... 11 | 10 ... 7 | 6 ... 3 | 2 ... 0 |
+ | Op 0 | Op1 | CRn | CRm | Op2 |
+
+ All system regs accessed through this API are (rw, 64-bit) and
+ kvm_device_attr.addr points to a __u64 value.
+
+ KVM_DEV_ARM_VGIC_CPU_SYSREGS accesses the CPU interface registers for the
+ CPU specified by the mpidr field.
+
+ Errors:
+ -ENXIO: Getting or setting this register is not yet supported
+ -EBUSY: VCPU is running
+ -EINVAL: Invalid mpidr supplied
+
+
+ KVM_DEV_ARM_VGIC_GRP_NR_IRQS
+ Attributes:
+ A value describing the number of interrupts (SGI, PPI and SPI) for
+ this GIC instance, ranging from 64 to 1024, in increments of 32.
+
+ kvm_device_attr.addr points to a __u32 value.
+
+ Errors:
+ -EINVAL: Value set is out of the expected range
+ -EBUSY: Value has already be set.
+
+
+ KVM_DEV_ARM_VGIC_GRP_CTRL
+ Attributes:
+ KVM_DEV_ARM_VGIC_CTRL_INIT
+ request the initialization of the VGIC, no additional parameter in
+ kvm_device_attr.addr.
+ Errors:
+ -ENXIO: VGIC not properly configured as required prior to calling
+ this attribute
+ -ENODEV: no online VCPU
+ -ENOMEM: memory shortage when allocating vgic internal data
+
+
+ KVM_DEV_ARM_VGIC_GRP_LEVEL_INFO
+ Attributes:
+ The attr field of kvm_device_attr encodes the following values:
+ bits: | 63 .... 32 | 31 .... 10 | 9 .... 0 |
+ values: | mpidr | info | vINTID |
+
+ The vINTID specifies which set of IRQs is reported on.
+
+ The info field specifies which information userspace wants to get or set
+ using this interface. Currently we support the following info values:
+
+ VGIC_LEVEL_INFO_LINE_LEVEL:
+ Get/Set the input level of the IRQ line for a set of 32 contiguously
+ numbered interrupts.
+ vINTID must be a multiple of 32.
+
+ kvm_device_attr.addr points to a __u32 value which will contain a
+ bitmap where a set bit means the interrupt level is asserted.
+
+ Bit[n] indicates the status for interrupt vINTID + n.
+
+ SGIs and any interrupt with a higher ID than the number of interrupts
+ supported, will be RAZ/WI. LPIs are always edge-triggered and are
+ therefore not supported by this interface.
+
+ PPIs are reported per VCPU as specified in the mpidr field, and SPIs are
+ reported with the same value regardless of the mpidr specified.
+
+ The mpidr field encodes the CPU ID based on the affinity information in the
+ architecture defined MPIDR, and the field is encoded as follows:
+ | 63 .... 56 | 55 .... 48 | 47 .... 40 | 39 .... 32 |
+ | Aff3 | Aff2 | Aff1 | Aff0 |
diff --git a/Documentation/virtual/kvm/devices/arm-vgic.txt b/Documentation/virtual/kvm/devices/arm-vgic.txt
index 89182f8..76e61c8 100644
--- a/Documentation/virtual/kvm/devices/arm-vgic.txt
+++ b/Documentation/virtual/kvm/devices/arm-vgic.txt
@@ -1,24 +1,19 @@
-ARM Virtual Generic Interrupt Controller (VGIC)
-===============================================
+ARM Virtual Generic Interrupt Controller v2 (VGIC)
+==================================================
Device types supported:
KVM_DEV_TYPE_ARM_VGIC_V2 ARM Generic Interrupt Controller v2.0
- KVM_DEV_TYPE_ARM_VGIC_V3 ARM Generic Interrupt Controller v3.0
- KVM_DEV_TYPE_ARM_VGIC_ITS ARM Interrupt Translation Service Controller
-Only one VGIC instance of the V2/V3 types above may be instantiated through
-either this API or the legacy KVM_CREATE_IRQCHIP api. The created VGIC will
-act as the VM interrupt controller, requiring emulated user-space devices to
-inject interrupts to the VGIC instead of directly to CPUs.
+Only one VGIC instance may be instantiated through either this API or the
+legacy KVM_CREATE_IRQCHIP API. The created VGIC will act as the VM interrupt
+controller, requiring emulated user-space devices to inject interrupts to the
+VGIC instead of directly to CPUs.
-Creating a guest GICv3 device requires a host GICv3 as well.
-GICv3 implementations with hardware compatibility support allow a guest GICv2
-as well.
+GICv3 implementations with hardware compatibility support allow creating a
+guest GICv2 through this interface. For information on creating a guest GICv3
+device and guest ITS devices, see arm-vgic-v3.txt. It is not possible to
+create both a GICv3 and GICv2 device on the same VM.
-Creating a virtual ITS controller requires a host GICv3 (but does not depend
-on having physical ITS controllers).
-There can be multiple ITS controllers per guest, each of them has to have
-a separate, non-overlapping MMIO region.
Groups:
KVM_DEV_ARM_VGIC_GRP_ADDR
@@ -32,26 +27,13 @@ Groups:
Base address in the guest physical address space of the GIC virtual cpu
interface register mappings. Only valid for KVM_DEV_TYPE_ARM_VGIC_V2.
This address needs to be 4K aligned and the region covers 4 KByte.
-
- KVM_VGIC_V3_ADDR_TYPE_DIST (rw, 64-bit)
- Base address in the guest physical address space of the GICv3 distributor
- register mappings. Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
- This address needs to be 64K aligned and the region covers 64 KByte.
-
- KVM_VGIC_V3_ADDR_TYPE_REDIST (rw, 64-bit)
- Base address in the guest physical address space of the GICv3
- redistributor register mappings. There are two 64K pages for each
- VCPU and all of the redistributor pages are contiguous.
- Only valid for KVM_DEV_TYPE_ARM_VGIC_V3.
- This address needs to be 64K aligned.
-
- KVM_VGIC_V3_ADDR_TYPE_ITS (rw, 64-bit)
- Base address in the guest physical address space of the GICv3 ITS
- control register frame. The ITS allows MSI(-X) interrupts to be
- injected into guests. This extension is optional. If the kernel
- does not support the ITS, the call returns -ENODEV.
- Only valid for KVM_DEV_TYPE_ARM_VGIC_ITS.
- This address needs to be 64K aligned and the region covers 128K.
+ Errors:
+ -E2BIG: Address outside of addressable IPA range
+ -EINVAL: Incorrectly aligned address
+ -EEXIST: Address already configured
+ -ENXIO: The group or attribute is unknown/unsupported for this device
+ or hardware support is missing.
+ -EFAULT: Invalid user pointer for attr->addr.
KVM_DEV_ARM_VGIC_GRP_DIST_REGS
Attributes:
--
2.9.0
^ permalink raw reply related
* [PULL 00/50] KVM/ARM Changes for v4.9
From: Christoffer Dall @ 2016-09-27 18:05 UTC (permalink / raw)
To: linux-arm-kernel
Hi Paolo and Radim,
Here are the KVM/ARM Changes for v4.9. They include:
- Various cleanups and removal of redundant code
- Two important fixes for not using an in-kernel irqchip
- A bit of optimizations
- Handle SError exceptions and present them to guests if appropriate
- Proxying of GICV access at EL2 if guest mappings are unsafe
- GICv3 on AArch32 on ARMv8
- Preparations for GICv3 save/restore, including ABI docs
The following changes since commit 9ac7e3e815060efdc86b6d12448200e3c3597e01:
KVM: nVMX: expose INS/OUTS information support (2016-09-07 19:34:30 +0200)
are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/kvmarm/kvmarm.git tags/kvm-arm-for-v4.9
for you to fetch changes up to 0099b7701f5296a758d9e6b945ec96f96847cc2f:
KVM: arm/arm64: vgic: Don't flush/sync without a working vgic (2016-09-27 18:57:35 +0200)
Thanks,
-Christoffer
---
Christoffer Dall (6):
KVM: arm/arm64: Add VGICv3 save/restore API documentation
KVM: arm/arm64: Factor out vgic_attr_regs_access functionality
KVM: arm/arm64: Rename vgic_attr_regs_access to vgic_attr_regs_access_v2
KVM: arm/arm64: Get rid of exported aliases to static functions
KVM: arm64: Require in-kernel irqchip for PMU support
KVM: arm/arm64: vgic: Don't flush/sync without a working vgic
Marc Zyngier (28):
KVM: arm: vgic: Drop build compatibility hack for older kernel versions
arm64: KVM: Move kvm_vcpu_get_condition out of emulate.c
arm64: KVM: Move the AArch32 conditional execution to common code
arm: KVM: Use common AArch32 conditional execution code
arm64: KVM: Make kvm_skip_instr32 available to HYP
arm64: KVM: vgic-v2: Add the GICV emulation infrastructure
arm64: KVM: vgic-v2: Add GICV access from HYP
arm64: KVM: vgic-v2: Enable GICV access from HYP if access from guest is unsafe
arm64: KVM: Rename HCR_VA to HCR_VSE
arm64: KVM: Preserve pending vSError in world switch
arm64: KVM: Add Virtual Abort injection helper
arm64: KVM: Add exception code to report EL1 asynchronous aborts
arm64: KVM: Add EL1 async abort handler
arm64: KVM: Route asynchronous aborts
arm64: KVM: Allow an exit code to be tagged with an SError
arm64: KVM: Inject a Virtual SError if it was pending
arm64: KVM: Handle async aborts delivered while at EL2
arm: KVM: Preserve pending Virtual Abort in world switch
arm: KVM: Add Virtual Abort injection helper
arm: KVM: Add HYP async abort handler
arm: KVM: Allow an exit code to be tagged with a Virtual Abort
arm: KVM: Handle async aborts delivered while at HYP
arm: KVM: Inject a Virtual Abort if it was pending
arm: KVM: Drop unreachable HYP abort handlers
arm/arm64: KVM: Inject virtual abort when guest exits on external abort
arm/arm64: KVM: Remove external abort test from MMIO handling
arm64: KVM: Inject a vSerror if detecting a bad GICV access at EL2
ARM: gic-v3: Work around definition of gic_write_bpr1
Mark Rutland (2):
arm/kvm: excise redundant cache maintenance
arm64/kvm: remove unused stub functions
Paolo Bonzini (1):
KVM: ARM: cleanup kvm_timer_hyp_init
Shanker Donthineni (1):
arm64: KVM: Optimize __guest_enter/exit() to save a few instructions
Vladimir Murzin (12):
arm64: KVM: VHE: reset PSTATE.PAN on entry to EL2
arm64: KVM: Use static keys for selecting the GIC backend
arm64: KVM: Move GIC accessors to arch_gicv3.h
arm64: KVM: Move vgic-v3 save/restore to virt/kvm/arm/hyp
KVM: arm64: vgic-its: Introduce config option to guard ITS specific code
KVM: arm: vgic: Fix compiler warnings when built for 32-bit
KVM: arm: vgic: Support 64-bit data manipulation on 32-bit host systems
ARM: Introduce MPIDR_LEVEL_SHIFT macro
ARM: Move system register accessors to asm/cp15.h
ARM: gic-v3: Introduce 32-to-64-bit mappings for GICv3 cpu registers
ARM: KVM: Support vgic-v3
arm64: KVM: Remove duplicating init code for setting VMID
Documentation/virtual/kvm/devices/arm-vgic-its.txt | 38 ++++
Documentation/virtual/kvm/devices/arm-vgic-v3.txt | 206 +++++++++++++++++++++
Documentation/virtual/kvm/devices/arm-vgic.txt | 52 ++----
Documentation/virtual/kvm/devices/vcpu.txt | 4 +-
arch/arm/include/asm/arch_gicv3.h | 100 ++++++++--
arch/arm/include/asm/cp15.h | 15 ++
arch/arm/include/asm/cputype.h | 1 +
arch/arm/include/asm/kvm_asm.h | 7 +
arch/arm/include/asm/kvm_emulate.h | 35 +++-
arch/arm/include/asm/kvm_host.h | 5 +
arch/arm/include/asm/kvm_hyp.h | 18 +-
arch/arm/include/asm/kvm_mmu.h | 28 +--
arch/arm/include/uapi/asm/kvm.h | 7 +
arch/arm/kvm/Makefile | 3 +
arch/arm/kvm/arm.c | 12 +-
arch/arm/kvm/coproc.c | 35 ++++
arch/arm/kvm/emulate.c | 111 ++---------
arch/arm/kvm/handle_exit.c | 49 +++--
arch/arm/kvm/hyp/Makefile | 1 +
arch/arm/kvm/hyp/entry.S | 31 ++++
arch/arm/kvm/hyp/hyp-entry.S | 16 +-
arch/arm/kvm/hyp/switch.c | 25 ++-
arch/arm/kvm/hyp/tlb.c | 15 +-
arch/arm/kvm/mmio.c | 6 -
arch/arm/kvm/mmu.c | 7 +-
arch/arm64/include/asm/arch_gicv3.h | 13 ++
arch/arm64/include/asm/kvm_arm.h | 4 +-
arch/arm64/include/asm/kvm_asm.h | 9 +-
arch/arm64/include/asm/kvm_emulate.h | 11 ++
arch/arm64/include/asm/kvm_hyp.h | 1 +
arch/arm64/include/asm/kvm_mmu.h | 6 -
arch/arm64/kvm/Kconfig | 4 +-
arch/arm64/kvm/Makefile | 3 +-
arch/arm64/kvm/handle_exit.c | 23 +++
arch/arm64/kvm/hyp/Makefile | 2 +-
arch/arm64/kvm/hyp/debug-sr.c | 4 +-
arch/arm64/kvm/hyp/entry.S | 128 ++++++++-----
arch/arm64/kvm/hyp/hyp-entry.S | 73 +++++---
arch/arm64/kvm/hyp/switch.c | 84 +++++++--
arch/arm64/kvm/hyp/tlb.c | 13 +-
arch/arm64/kvm/inject_fault.c | 12 ++
include/kvm/arm_vgic.h | 18 +-
arch/arm64/kvm/emulate.c => virt/kvm/arm/aarch32.c | 25 +--
virt/kvm/arm/arch_timer.c | 6 +-
virt/kvm/arm/hyp/vgic-v2-sr.c | 57 ++++++
{arch/arm64/kvm => virt/kvm/arm}/hyp/vgic-v3-sr.c | 17 +-
virt/kvm/arm/pmu.c | 8 +
virt/kvm/arm/vgic/vgic-init.c | 4 +
virt/kvm/arm/vgic/vgic-irqfd.c | 6 -
virt/kvm/arm/vgic/vgic-kvm-device.c | 133 ++++++++-----
virt/kvm/arm/vgic/vgic-mmio-v3.c | 8 +-
virt/kvm/arm/vgic/vgic-mmio.c | 2 -
virt/kvm/arm/vgic/vgic-mmio.h | 4 +-
virt/kvm/arm/vgic/vgic-v2.c | 71 ++++---
virt/kvm/arm/vgic/vgic.c | 8 +-
virt/kvm/arm/vgic/vgic.h | 54 +-----
56 files changed, 1076 insertions(+), 562 deletions(-)
create mode 100644 Documentation/virtual/kvm/devices/arm-vgic-its.txt
create mode 100644 Documentation/virtual/kvm/devices/arm-vgic-v3.txt
rename arch/arm64/kvm/emulate.c => virt/kvm/arm/aarch32.c (90%)
rename {arch/arm64/kvm => virt/kvm/arm}/hyp/vgic-v3-sr.c (94%)
^ permalink raw reply
* [PATCH 2/2] ARM: BCM5301X: Add DT for Luxul XWR-3100
From: Dan Haab @ 2016-09-27 17:27 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474997231-27700-1-git-send-email-dhaab@luxul.com>
Luxul XWR-3100 is a wireless router based on BCM47094 SoC with two
4366c0 FullMAC PCIe cards on the PCB. It uses NAND with BCH-4 ECC
algorithm.
Signed-off-by: Dan Haab <dhaab@luxul.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts | 111 +++++++++++++++++++++++++
arch/arm/boot/dts/bcm5301x-nand-cs0-bch4.dtsi | 13 +++
3 files changed, 125 insertions(+)
create mode 100644 arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
create mode 100644 arch/arm/boot/dts/bcm5301x-nand-cs0-bch4.dtsi
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index b7fbc1b..e46e2d85 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -88,6 +88,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
bcm4709-netgear-r7000.dtb \
bcm4709-netgear-r8000.dtb \
bcm47094-dlink-dir-885l.dtb \
+ bcm47094-luxul-xwr-3100.dtb \
bcm47094-netgear-r8500.dtb \
bcm94708.dtb \
bcm94709.dtb \
diff --git a/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
new file mode 100644
index 0000000..169b35f
--- /dev/null
+++ b/arch/arm/boot/dts/bcm47094-luxul-xwr-3100.dts
@@ -0,0 +1,111 @@
+/*
+ * Copyright 2016 Luxul Inc.
+ *
+ * Licensed under the ISC license.
+ */
+
+/dts-v1/;
+
+#include "bcm47094.dtsi"
+#include "bcm5301x-nand-cs0-bch4.dtsi"
+
+/ {
+ compatible = "luxul,xwr-3100v1", "brcm,bcm47094", "brcm,bcm4708";
+ model = "Luxul XWR-3100 V1";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 earlycon";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ power {
+ label = "bcm53xx:green:power";
+ gpios = <&chipcommon 0 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-on";
+ };
+
+ lan3 {
+ label = "bcm53xx:green:lan1";
+ gpios = <&chipcommon 1 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ lan4 {
+ label = "bcm53xx:green:lan0";
+ gpios = <&chipcommon 2 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ wan {
+ label = "bcm53xx:green:wan";
+ gpios = <&chipcommon 3 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ lan1 {
+ label = "bcm53xx:green:lan3";
+ gpios = <&chipcommon 4 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ lan2 {
+ label = "bcm53xx:green:lan2";
+ gpios = <&chipcommon 6 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ usb3 {
+ label = "bcm53xx:green:usb3";
+ gpios = <&chipcommon 8 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ status {
+ label = "bcm53xx:green:status";
+ gpios = <&chipcommon 10 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "timer";
+ };
+
+ 2ghz {
+ label = "bcm53xx:green:2ghz";
+ gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+
+ 5ghz {
+ label = "bcm53xx:green:5ghz";
+ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "default-off";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 17 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&usb3 {
+ vcc-gpio = <&chipcommon 18 GPIO_ACTIVE_HIGH>;
+};
+
+&spi_nor {
+ status = "okay";
+};
diff --git a/arch/arm/boot/dts/bcm5301x-nand-cs0-bch4.dtsi b/arch/arm/boot/dts/bcm5301x-nand-cs0-bch4.dtsi
new file mode 100644
index 0000000..b4e875d
--- /dev/null
+++ b/arch/arm/boot/dts/bcm5301x-nand-cs0-bch4.dtsi
@@ -0,0 +1,13 @@
+/*
+ * Copyright 2016 Luxul Inc.
+ *
+ * Licensed under the ISC license.
+ */
+
+#include "bcm5301x-nand-cs0.dtsi"
+
+&nandcs {
+ nand-ecc-algo = "bch";
+ nand-ecc-strength = <4>;
+ nand-ecc-step-size = <512>;
+};
--
1.7.9.5
^ permalink raw reply related
* [PATCH 1/2] ARM: BCM5301X: Add DT for Luxul XAP-1510
From: Dan Haab @ 2016-09-27 17:27 UTC (permalink / raw)
To: linux-arm-kernel
Luxul XAP-1510 is an AP device based on BCM4708 SoC with 2 x BCM4360
chipsets on PCB connected using PCIe.
Signed-off-by: Dan Haab <dhaab@luxul.com>
---
arch/arm/boot/dts/Makefile | 1 +
arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts | 64 ++++++++++++++++++++++++++
2 files changed, 65 insertions(+)
create mode 100644 arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
diff --git a/arch/arm/boot/dts/Makefile b/arch/arm/boot/dts/Makefile
index 9bfd1ef..b7fbc1b 100644
--- a/arch/arm/boot/dts/Makefile
+++ b/arch/arm/boot/dts/Makefile
@@ -75,6 +75,7 @@ dtb-$(CONFIG_ARCH_BCM_5301X) += \
bcm4708-asus-rt-ac56u.dtb \
bcm4708-asus-rt-ac68u.dtb \
bcm4708-buffalo-wzr-1750dhp.dtb \
+ bcm4708-luxul-xap-1510.dtb \
bcm4708-luxul-xwc-1000.dtb \
bcm4708-netgear-r6250.dtb \
bcm4708-netgear-r6300-v2.dtb \
diff --git a/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts b/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
new file mode 100644
index 0000000..35e6ed6
--- /dev/null
+++ b/arch/arm/boot/dts/bcm4708-luxul-xap-1510.dts
@@ -0,0 +1,64 @@
+/*
+ * Copyright 2016 Luxul Inc.
+ *
+ * Licensed under the ISC license.
+ */
+
+/dts-v1/;
+
+#include "bcm4708.dtsi"
+
+/ {
+ compatible = "luxul,xap-1510v1", "brcm,bcm4708";
+ model = "Luxul XAP-1510 V1";
+
+ chosen {
+ bootargs = "console=ttyS0,115200 earlycon";
+ };
+
+ memory {
+ reg = <0x00000000 0x08000000>;
+ };
+
+ leds {
+ compatible = "gpio-leds";
+
+ 5ghz {
+ label = "bcm53xx:blue:5ghz";
+ gpios = <&chipcommon 13 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "none";
+ };
+
+ 2ghz {
+ label = "bcm53xx:blue:2ghz";
+ gpios = <&chipcommon 14 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "none";
+ };
+
+ status {
+ label = "bcm53xx:green:status";
+ gpios = <&chipcommon 15 GPIO_ACTIVE_LOW>;
+ linux,default-trigger = "timer";
+ };
+ };
+
+ gpio-keys {
+ compatible = "gpio-keys";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ restart {
+ label = "Reset";
+ linux,code = <KEY_RESTART>;
+ gpios = <&chipcommon 11 GPIO_ACTIVE_LOW>;
+ };
+ };
+};
+
+&uart0 {
+ status = "okay";
+};
+
+&spi_nor {
+ status = "okay";
+};
--
1.7.9.5
^ permalink raw reply related
* [PATCH v2 8/8] ARM: bcm2835: Disable i2c2 in the Device Tree
From: Stefan Wahren @ 2016-09-27 17:25 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474977426-3272-9-git-send-email-noralf@tronnes.org>
> Noralf Tr?nnes <noralf@tronnes.org> hat am 27. September 2016 um 13:57
> geschrieben:
>
>
> i2c2 is connected to the HDMI connector and is controlled by the
> firmware. Disable it to stay out of harms way.
Until this point the commit message is okay, the rest is more confusing.
Btw this should avoid a warning about missing clock frequency.
>
> From the downstream commit:
> i2c-bcm2708/BCM270X_DT: Add support for I2C2
>
> The third I2C bus (I2C2) is normally reserved for HDMI use. Careless
> use of this bus can break an attached display - use with caution.
>
> It is recommended to disable accesses by VideoCore by setting
> hdmi_ignore_edid=1 or hdmi_edid_file=1 in config.txt.
>
> Signed-off-by: Noralf Tr?nnes <noralf@tronnes.org>
> ---
> arch/arm/boot/dts/bcm2835-rpi.dtsi | 4 ----
> 1 file changed, 4 deletions(-)
>
> diff --git a/arch/arm/boot/dts/bcm2835-rpi.dtsi
> b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> index e9b47b2..8bffbee 100644
> --- a/arch/arm/boot/dts/bcm2835-rpi.dtsi
> +++ b/arch/arm/boot/dts/bcm2835-rpi.dtsi
> @@ -59,10 +59,6 @@
> clock-frequency = <100000>;
> };
>
> -&i2c2 {
> - status = "okay";
> -};
> -
I'm not sure if this the right fix. According to bcm283x.dtsi the 3 i2c busses
have the same compatible string "brcm,bcm2835-i2c", but the changelog suggests
that this bus is "special".
Shouldn't we use a different compatible string? Our intention isn't to disable
i2c2 but avoid any claims of the usual i2c driver.
> &sdhci {
> status = "okay";
> bus-width = <4>;
> --
> 2.8.2
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH v9 17/19] drm/virtio: kconfig: Fix recursive dependency issue.
From: Bjorn Andersson @ 2016-09-27 17:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <CACvgo53fuoPVjBAkZbWFPVxosObjvxoDgFdR_BkSTgevqyGg9g@mail.gmail.com>
On Wed 21 Sep 05:09 PDT 2016, Emil Velikov wrote:
> On 20 September 2016 at 09:32, Peter Griffin <peter.griffin@linaro.org> wrote:
> > Hi Emil,
> >
> > On Tue, 20 Sep 2016, Emil Velikov wrote:
> >
> >> On 5 September 2016 at 14:16, Peter Griffin <peter.griffin@linaro.org> wrote:
> >> > ST_SLIM_REMOTEPROC must select REMOTEPROC, which exposes the following
> >> > recursive dependency.
> >
> >
> >> >
> >> From a humble skim through remoteproc, drm and a few other subsystems
> >> I think the above is wrong. All the drivers (outside of remoteproc),
> >> that I've seen, depend on the core component, they don't select it.
> >
> > I will let Bjorn comment on the remoteproc subsystem Kconfig design, and
> > why it is like it is.
> >
> > For this particular SLIM_RPROC I have added it to Kconfig in keeping with all
> > the other drivers in the remoteproc subsystem which has exposed this recursive
> > dependency issue.
> >
> > For this particular kconfig symbol a quick grep reveals more drivers in
> > the kernel using 'select', than 'depend on'
> >
> > git grep "select VIRTIO" | wc -l
> > 14
> >
> > git grep "depends on VIRTIO" | wc -l
> > 10
> >
> Might be worth taking a closer look into these at some point.
>
The general idea here is that VIRTIO provides the "framework" and as
such drivers implementing VIRTIO do select and drivers using virtio use
depends.
This is found in several places around the kernel.
> >
> >> Furthermore most places explicitly hide the drivers from the menu if
> >> the core component isn't enabled.
> >
> > Remoteproc subsystem takes a different approach, the core code is only enabled
> > if a driver which relies on it is enabled. This IMHO makes sense, as
> > remoteproc is not widely used (only a few particular ARM SoC's).
> >
> > It is true that for subsystems which rely on the core component being
> > explicitly enabled, they often tend to hide drivers which depend on it
> > from the menu unless it is. This also makes sense.
> >
> >>
> >> Is there something that requires such a different/unusual behaviour in
> >> remoteproc ?
> >>
There's nothing unusual in remoteproc that forces us to stay with this
model; however the parts related to the REMOTEPROC config is useless by
themselves.
Regards,
Bjorn
^ permalink raw reply
* ARM juno R2 board USB Issue (EHCI probe failed)
From: Sudeep Holla @ 2016-09-27 17:01 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <9b231601-2c6a-a5d7-471f-4fc0d8190d83@arm.com>
On 27/09/16 17:23, Robin Murphy wrote:
> On 27/09/16 17:13, Hanjun Guo wrote:
>> On 09/27/2016 05:07 PM, Sudeep Holla wrote:
[...]
>>>>
>>>> As I mentioned in private, I do get the same error if I drop _CCA in
>>>> USB object of ACPI DSDT. Can you give it a spin with latest UEFI ?
>>>>
>>>> Sure, will try with latest UEFI.
>>>>
>>>
>>> I bet that's 8-12 months old. It puts the banner during boot with the
>>> build date. You can try to follow [1] or access it from [2]
>>
>> Agree.
>>
>> D03 is using the same IP (EHCI) and the USB works fine with _CCA
>> in the device node.
>
> _CCA is mandatory on arm64 (see CONFIG_ACPI_CCA_REQUIRED). Any devices
> without it are going to end up with the dummy DMA ops which
> intentionally fail if a driver tries to use them - i.e. the error seen
> above is by design.
>
Yes that was the first thing I thought and gave it try with _CCA removed
in ACPI DSDT on my Juno R2. It so happens that we did ship it some
*custom* UEFI until Linaro 16.02 in which upstream EDK2 was merged :(
Since Vikas was trying boot out of USB, I didn't suggest him to take a
acpidump on Juno and confirm this by looking at the DSDT. Also I could
find a commit from Leif that adds _CCA to USB in OpenPlatformPkg to
confirm this.
--
Regards,
Sudeep
^ permalink raw reply
* [PATCH 2/2] drm/rockchip: mark symbols static where possible
From: Sean Paul @ 2016-09-27 16:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474789388-3284-1-git-send-email-baoyou.xie@linaro.org>
On Sun, Sep 25, 2016 at 3:43 AM, Baoyou Xie <baoyou.xie@linaro.org> wrote:
> We get 2 warnings when building kernel with W=1:
> drivers/gpu/drm/rockchip/rockchip_drm_drv.c:309:6: warning: no previous prototype for 'rockchip_drm_fb_suspend' [-Wmissing-prototypes]
> drivers/gpu/drm/rockchip/rockchip_drm_drv.c:318:6: warning: no previous prototype for 'rockchip_drm_fb_resume' [-Wmissing-prototypes]
>
> In fact, these functions are only used in the file in which they are
> declared and don't need a declaration, but can be made static.
> So this patch marks these functions with 'static'.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
Applied to -misc, thanks.
Sean
> ---
> drivers/gpu/drm/rockchip/rockchip_drm_drv.c | 4 ++--
> 1 file changed, 2 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> index 76eaf1d..38c3be5 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_drv.c
> @@ -309,7 +309,7 @@ static struct drm_driver rockchip_drm_driver = {
> };
>
> #ifdef CONFIG_PM_SLEEP
> -void rockchip_drm_fb_suspend(struct drm_device *drm)
> +static void rockchip_drm_fb_suspend(struct drm_device *drm)
> {
> struct rockchip_drm_private *priv = drm->dev_private;
>
> @@ -318,7 +318,7 @@ void rockchip_drm_fb_suspend(struct drm_device *drm)
> console_unlock();
> }
>
> -void rockchip_drm_fb_resume(struct drm_device *drm)
> +static void rockchip_drm_fb_resume(struct drm_device *drm)
> {
> struct rockchip_drm_private *priv = drm->dev_private;
>
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH] drm/mediatek: mark symbols static where possible
From: Sean Paul @ 2016-09-27 16:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474789265-30142-1-git-send-email-baoyou.xie@linaro.org>
On Sun, Sep 25, 2016 at 3:41 AM, Baoyou Xie <baoyou.xie@linaro.org> wrote:
> We get 4 warnings when building kernel with W=1:
> drivers/gpu/drm/mediatek/mtk_hdmi.c:1089:6: warning: no previous prototype for 'mtk_hdmi_audio_enable' [-Wmissing-prototypes]
> drivers/gpu/drm/mediatek/mtk_hdmi.c:1095:6: warning: no previous prototype for 'mtk_hdmi_audio_disable' [-Wmissing-prototypes]
> drivers/gpu/drm/mediatek/mtk_hdmi.c:1101:5: warning: no previous prototype for 'mtk_hdmi_audio_set_param' [-Wmissing-prototypes]
> drivers/gpu/drm/mediatek/mtk_hdmi.c:1627:5: warning: no previous prototype for 'mtk_hdmi_audio_digital_mute' [-Wmissing-prototypes]
>
> In fact, both functions are only used in the file in which they are
> declared and don't need a declaration, but can be made static.
> So this patch marks both functions with 'static'.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
Applied to -misc, thanks.
Sean
> ---
> drivers/gpu/drm/mediatek/mtk_hdmi.c | 9 +++++----
> 1 file changed, 5 insertions(+), 4 deletions(-)
>
> diff --git a/drivers/gpu/drm/mediatek/mtk_hdmi.c b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> index 334562d..be4e19c 100644
> --- a/drivers/gpu/drm/mediatek/mtk_hdmi.c
> +++ b/drivers/gpu/drm/mediatek/mtk_hdmi.c
> @@ -1086,19 +1086,19 @@ static int mtk_hdmi_output_init(struct mtk_hdmi *hdmi)
> return 0;
> }
>
> -void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi)
> +static void mtk_hdmi_audio_enable(struct mtk_hdmi *hdmi)
> {
> mtk_hdmi_aud_enable_packet(hdmi, true);
> hdmi->audio_enable = true;
> }
>
> -void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi)
> +static void mtk_hdmi_audio_disable(struct mtk_hdmi *hdmi)
> {
> mtk_hdmi_aud_enable_packet(hdmi, false);
> hdmi->audio_enable = false;
> }
>
> -int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi,
> +static int mtk_hdmi_audio_set_param(struct mtk_hdmi *hdmi,
> struct hdmi_audio_param *param)
> {
> if (!hdmi->audio_enable) {
> @@ -1624,7 +1624,8 @@ static void mtk_hdmi_audio_shutdown(struct device *dev, void *data)
> mtk_hdmi_audio_disable(hdmi);
> }
>
> -int mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable)
> +static int
> +mtk_hdmi_audio_digital_mute(struct device *dev, void *data, bool enable)
> {
> struct mtk_hdmi *hdmi = dev_get_drvdata(dev);
>
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH 1/2] drm/rockchip: add missing header dependencies
From: Sean Paul @ 2016-09-27 16:34 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474789109-22010-1-git-send-email-baoyou.xie@linaro.org>
On Sun, Sep 25, 2016 at 3:38 AM, Baoyou Xie <baoyou.xie@linaro.org> wrote:
> We get 2 warnings when building kernel with W=1:
> drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c:130:5: warning: no previous prototype for 'rockchip_drm_fbdev_init' [-Wmissing-prototypes]
> drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c:173:6: warning: no previous prototype for 'rockchip_drm_fbdev_fini' [-Wmissing-prototypes]
>
> In fact, these functions are declared
> in drivers/gpu/drm/rockchip/rockchip_drm_fbdev.h,
> so this patch adds missing header dependencies.
>
> Signed-off-by: Baoyou Xie <baoyou.xie@linaro.org>
Applied to -misc, thanks.
Sean
> ---
> drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c | 1 +
> 1 file changed, 1 insertion(+)
>
> diff --git a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
> index 207e01d..a16c69f 100644
> --- a/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
> +++ b/drivers/gpu/drm/rockchip/rockchip_drm_fbdev.c
> @@ -20,6 +20,7 @@
> #include "rockchip_drm_drv.h"
> #include "rockchip_drm_gem.h"
> #include "rockchip_drm_fb.h"
> +#include "rockchip_drm_fbdev.h"
>
> #define PREFERRED_BPP 32
> #define to_drm_private(x) \
> --
> 2.7.4
>
^ permalink raw reply
* [PATCH] usb: Convert pr_warning to pr_warn
From: Robert Jarzmik @ 2016-09-27 16:26 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <f86b512272987e0faeaccbe6466665175eaefe9a.1474992979.git.joe@perches.com>
Joe Perches <joe@perches.com> writes:
> Use the more common logging mechanism.
>
> Miscellanea:
>
> o Realign multiline statements
> o Coalesce format
>
> Signed-off-by: Joe Perches <joe@perches.com>
For pxa25x_udc.h:
Acked-by: Robert Jarzmik <robert.jarzmik@free.fr>
Cheers.
--
Robert
^ permalink raw reply
* ARM juno R2 board USB Issue (EHCI probe failed)
From: Robin Murphy @ 2016-09-27 16:23 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <57EA9AAA.5090504@linaro.org>
On 27/09/16 17:13, Hanjun Guo wrote:
> On 09/27/2016 05:07 PM, Sudeep Holla wrote:
>>
>>
>> On 27/09/16 09:55, Sajjan, Vikas C wrote:
>>> Hi Sudeep,
>>>
>>> -----Original Message-----
>>> From: Sudeep Holla [mailto:sudeep.holla at arm.com]
>>> Sent: Tuesday, September 27, 2016 2:21 PM
>>> To: Vikas Sajjan <sajjan.linux@gmail.com>; linux-usb at vger.kernel.org;
>>> linux-arm-kernel at lists.infradead.org; linux-acpi at vger.kernel.org
>>> Cc: Sudeep Holla <sudeep.holla@arm.com>; mark.rutland at arm.com;
>>> lorenzo.pieralisi at arm.com; Sajjan, Vikas C <vikas.cha.sajjan@hpe.com>
>>> Subject: Re: ARM juno R2 board USB Issue (EHCI probe failed)
>>>
>>> Hi Vikas,
>>>
>>> On 27/09/16 09:14, Vikas Sajjan wrote:
>>>> Adding USB mailing list.
>>>>
>>>>
>>>> On Tue, Sep 27, 2016 at 12:33 PM, Sajjan, Vikas C
>>>> <vikas.cha.sajjan@hpe.com> wrote:
>>>>> Hi All,
>>>>>
>>>>> I working on ARM juno R2 board, with latest kernel 4.8.rc7 and I get
>>>>> below USB EHCI probe error while booting with acpi=force.
>>>>>
>>>
>>> Are you using the latest UEFI EDK2 ?
>>> No, I am still using the UEFI binary which came as part of the Juno
>>> board.
>>>
>>>
>>>>> [ 1.223662] VFIO - User Level meta-driver version: 0.3
>>>>> [ 1.229335] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI)
>>>>> Driver
>>>>> [ 1.235882] ehci-pci: EHCI PCI platform driver
>>>>> [ 1.240359] ehci-platform: EHCI generic platform driver
>>>>> [ 1.245619] ehci-platform ARMH0D20:00: Error: DMA mask
>>>>> configuration failed
>>>>> [ 1.272491] ehci-platform: probe of ARMH0D20:00 failed with
>>>>> error -5
>>>>> [ 1.278876] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
>>>>> [ 1.285071] ohci-pci: OHCI PCI platform driver
>>>>> [ 1.289548] ohci-platform: OHCI generic platform driver
>>>>> [ 1.294884] usbcore: registered new interface driver usb-storage
>>>>> [ 1.301231] mousedev: PS/2 mouse device common for all mice
>>>>> [ 1.307197] rtc-efi rtc-efi: rtc core: registered rtc-efi as rtc0
>>>>>
>>>>> But this error goes off, if I don't force ACPI booting, i.e., if I
>>>>> remove acpi=force from kernel command line , USB is detected and my
>>>>> RFS which is in the usb drive, gets mounted successfully.
>>>>>
>>>
>>> As I mentioned in private, I do get the same error if I drop _CCA in
>>> USB object of ACPI DSDT. Can you give it a spin with latest UEFI ?
>>>
>>> Sure, will try with latest UEFI.
>>>
>>
>> I bet that's 8-12 months old. It puts the banner during boot with the
>> build date. You can try to follow [1] or access it from [2]
>
> Agree.
>
> D03 is using the same IP (EHCI) and the USB works fine with _CCA
> in the device node.
_CCA is mandatory on arm64 (see CONFIG_ACPI_CCA_REQUIRED). Any devices
without it are going to end up with the dummy DMA ops which
intentionally fail if a driver tries to use them - i.e. the error seen
above is by design.
Robin.
>
> Thanks
> Hanjun
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel at lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
^ permalink raw reply
* [PATCH] usb: Convert pr_warning to pr_warn
From: Joe Perches @ 2016-09-27 16:16 UTC (permalink / raw)
To: linux-arm-kernel
Use the more common logging mechanism.
Miscellanea:
o Realign multiline statements
o Coalesce format
Signed-off-by: Joe Perches <joe@perches.com>
---
drivers/usb/gadget/function/rndis.c | 9 ++++-----
drivers/usb/gadget/function/u_serial.c | 4 ++--
drivers/usb/gadget/udc/at91_udc.h | 2 +-
drivers/usb/gadget/udc/atmel_usba_udc.c | 4 ++--
drivers/usb/gadget/udc/fsl_usb2_udc.h | 2 +-
drivers/usb/gadget/udc/m66592-udc.c | 4 ++--
drivers/usb/gadget/udc/omap_udc.h | 2 +-
drivers/usb/gadget/udc/pxa25x_udc.h | 2 +-
drivers/usb/host/isp1362-hcd.c | 27 ++++++++++++++-------------
drivers/usb/isp1760/isp1760-if.c | 2 +-
10 files changed, 29 insertions(+), 29 deletions(-)
diff --git a/drivers/usb/gadget/function/rndis.c b/drivers/usb/gadget/function/rndis.c
index ab6ac1b74ac0..766c328c15c0 100644
--- a/drivers/usb/gadget/function/rndis.c
+++ b/drivers/usb/gadget/function/rndis.c
@@ -474,8 +474,7 @@ static int gen_ndis_query_resp(struct rndis_params *params, u32 OID, u8 *buf,
break;
default:
- pr_warning("%s: query unknown OID 0x%08X\n",
- __func__, OID);
+ pr_warn("%s: query unknown OID 0x%08X\n", __func__, OID);
}
if (retval < 0)
length = 0;
@@ -546,8 +545,8 @@ static int gen_ndis_set_resp(struct rndis_params *params, u32 OID,
break;
default:
- pr_warning("%s: set unknown OID 0x%08X, size %d\n",
- __func__, OID, buf_len);
+ pr_warn("%s: set unknown OID 0x%08X, size %d\n",
+ __func__, OID, buf_len);
}
return retval;
@@ -854,7 +853,7 @@ int rndis_msg_parser(struct rndis_params *params, u8 *buf)
* In one case those messages seemed to relate to the host
* suspending itself.
*/
- pr_warning("%s: unknown RNDIS message 0x%08X len %d\n",
+ pr_warn("%s: unknown RNDIS message 0x%08X len %d\n",
__func__, MsgType, MsgLength);
print_hex_dump_bytes(__func__, DUMP_PREFIX_OFFSET,
buf, MsgLength);
diff --git a/drivers/usb/gadget/function/u_serial.c b/drivers/usb/gadget/function/u_serial.c
index e0cd1e4c8892..62ec842874aa 100644
--- a/drivers/usb/gadget/function/u_serial.c
+++ b/drivers/usb/gadget/function/u_serial.c
@@ -622,8 +622,8 @@ static void gs_write_complete(struct usb_ep *ep, struct usb_request *req)
switch (req->status) {
default:
/* presumably a transient fault */
- pr_warning("%s: unexpected %s status %d\n",
- __func__, ep->name, req->status);
+ pr_warn("%s: unexpected %s status %d\n",
+ __func__, ep->name, req->status);
/* FALL THROUGH */
case 0:
/* normal completion */
diff --git a/drivers/usb/gadget/udc/at91_udc.h b/drivers/usb/gadget/udc/at91_udc.h
index 0a433e6b346b..9bbe72764f31 100644
--- a/drivers/usb/gadget/udc/at91_udc.h
+++ b/drivers/usb/gadget/udc/at91_udc.h
@@ -175,7 +175,7 @@ struct at91_request {
#endif
#define ERR(stuff...) pr_err("udc: " stuff)
-#define WARNING(stuff...) pr_warning("udc: " stuff)
+#define WARNING(stuff...) pr_warn("udc: " stuff)
#define INFO(stuff...) pr_info("udc: " stuff)
#define DBG(stuff...) pr_debug("udc: " stuff)
diff --git a/drivers/usb/gadget/udc/atmel_usba_udc.c b/drivers/usb/gadget/udc/atmel_usba_udc.c
index 45bc997d0711..1ef7a9a9d7f5 100644
--- a/drivers/usb/gadget/udc/atmel_usba_udc.c
+++ b/drivers/usb/gadget/udc/atmel_usba_udc.c
@@ -1464,8 +1464,8 @@ static void usba_control_irq(struct usba_udc *udc, struct usba_ep *ep)
pkt_len = USBA_BFEXT(BYTE_COUNT, usba_ep_readl(ep, STA));
DBG(DBG_HW, "Packet length: %u\n", pkt_len);
if (pkt_len != sizeof(crq)) {
- pr_warning("udc: Invalid packet length %u "
- "(expected %zu)\n", pkt_len, sizeof(crq));
+ pr_warn("udc: Invalid packet length %u (expected %zu)\n",
+ pkt_len, sizeof(crq));
set_protocol_stall(udc, ep);
return;
}
diff --git a/drivers/usb/gadget/udc/fsl_usb2_udc.h b/drivers/usb/gadget/udc/fsl_usb2_udc.h
index 84715625b2b3..e92b8408b6f6 100644
--- a/drivers/usb/gadget/udc/fsl_usb2_udc.h
+++ b/drivers/usb/gadget/udc/fsl_usb2_udc.h
@@ -554,7 +554,7 @@ static void dump_msg(const char *label, const u8 * buf, unsigned int length)
#endif
#define ERR(stuff...) pr_err("udc: " stuff)
-#define WARNING(stuff...) pr_warning("udc: " stuff)
+#define WARNING(stuff...) pr_warn("udc: " stuff)
#define INFO(stuff...) pr_info("udc: " stuff)
/*-------------------------------------------------------------------------*/
diff --git a/drivers/usb/gadget/udc/m66592-udc.c b/drivers/usb/gadget/udc/m66592-udc.c
index 6e977dc22570..de3e03483659 100644
--- a/drivers/usb/gadget/udc/m66592-udc.c
+++ b/drivers/usb/gadget/udc/m66592-udc.c
@@ -637,7 +637,7 @@ static void init_controller(struct m66592 *m66592)
clock = M66592_XTAL48;
break;
default:
- pr_warning("m66592-udc: xtal configuration error\n");
+ pr_warn("m66592-udc: xtal configuration error\n");
clock = 0;
}
@@ -649,7 +649,7 @@ static void init_controller(struct m66592 *m66592)
irq_sense = 0;
break;
default:
- pr_warning("m66592-udc: irq trigger config error\n");
+ pr_warn("m66592-udc: irq trigger config error\n");
irq_sense = 0;
}
diff --git a/drivers/usb/gadget/udc/omap_udc.h b/drivers/usb/gadget/udc/omap_udc.h
index cfadeb5fc5de..26974196cf44 100644
--- a/drivers/usb/gadget/udc/omap_udc.h
+++ b/drivers/usb/gadget/udc/omap_udc.h
@@ -187,7 +187,7 @@ struct omap_udc {
#endif
#define ERR(stuff...) pr_err("udc: " stuff)
-#define WARNING(stuff...) pr_warning("udc: " stuff)
+#define WARNING(stuff...) pr_warn("udc: " stuff)
#define INFO(stuff...) pr_info("udc: " stuff)
#define DBG(stuff...) pr_debug("udc: " stuff)
diff --git a/drivers/usb/gadget/udc/pxa25x_udc.h b/drivers/usb/gadget/udc/pxa25x_udc.h
index 4b8b72d7ab37..a458bec2536d 100644
--- a/drivers/usb/gadget/udc/pxa25x_udc.h
+++ b/drivers/usb/gadget/udc/pxa25x_udc.h
@@ -248,7 +248,7 @@ dump_state(struct pxa25x_udc *dev)
#define DBG(lvl, stuff...) do{if ((lvl) <= UDC_DEBUG) DMSG(stuff);}while(0)
#define ERR(stuff...) pr_err("udc: " stuff)
-#define WARNING(stuff...) pr_warning("udc: " stuff)
+#define WARNING(stuff...) pr_warn("udc: " stuff)
#define INFO(stuff...) pr_info("udc: " stuff)
diff --git a/drivers/usb/host/isp1362-hcd.c b/drivers/usb/host/isp1362-hcd.c
index 6cf82ee460a6..0f2b4b358e1a 100644
--- a/drivers/usb/host/isp1362-hcd.c
+++ b/drivers/usb/host/isp1362-hcd.c
@@ -147,7 +147,7 @@ static inline struct isp1362_ep_queue *get_ptd_queue(struct isp1362_hcd *isp1362
if (epq)
DBG(1, "%s: PTD $%04x is on %s queue\n", __func__, offset, epq->name);
else
- pr_warning("%s: invalid PTD $%04x\n", __func__, offset);
+ pr_warn("%s: invalid PTD $%04x\n", __func__, offset);
return epq;
}
@@ -157,8 +157,9 @@ static inline int get_ptd_offset(struct isp1362_ep_queue *epq, u8 index)
int offset;
if (index * epq->blk_size > epq->buf_size) {
- pr_warning("%s: Bad %s index %d(%d)\n", __func__, epq->name, index,
- epq->buf_size / epq->blk_size);
+ pr_warn("%s: Bad %s index %d(%d)\n",
+ __func__, epq->name, index,
+ epq->buf_size / epq->blk_size);
return -EINVAL;
}
offset = epq->buf_start + index * epq->blk_size;
@@ -902,8 +903,8 @@ static void start_iso_transfers(struct isp1362_hcd *isp1362_hcd)
ptd_offset = next_ptd(epq, ep);
if (ptd_offset < 0) {
- pr_warning("%s: req %d No more %s PTD buffers available\n", __func__,
- ep->num_req, epq->name);
+ pr_warn("%s: req %d No more %s PTD buffers available\n",
+ __func__, ep->num_req, epq->name);
break;
}
}
@@ -973,8 +974,8 @@ static void finish_transfers(struct isp1362_hcd *isp1362_hcd, unsigned long done
break;
}
if (done_map)
- pr_warning("%s: done_map not clear: %08lx:%08lx\n", __func__, done_map,
- epq->skip_map);
+ pr_warn("%s: done_map not clear: %08lx:%08lx\n",
+ __func__, done_map, epq->skip_map);
atomic_dec(&epq->finishing);
}
@@ -1433,7 +1434,7 @@ static int isp1362_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
} else
DBG(1, "%s: urb %p active; wait4irq\n", __func__, urb);
} else {
- pr_warning("%s: No EP in URB %p\n", __func__, urb);
+ pr_warn("%s: No EP in URB %p\n", __func__, urb);
retval = -EINVAL;
}
done:
@@ -1748,10 +1749,10 @@ static int isp1362_bus_suspend(struct usb_hcd *hcd)
/* FALL THROUGH */
case OHCI_USB_RESET:
status = -EBUSY;
- pr_warning("%s: needs reinit!\n", __func__);
+ pr_warn("%s: needs reinit!\n", __func__);
goto done;
case OHCI_USB_SUSPEND:
- pr_warning("%s: already suspended?\n", __func__);
+ pr_warn("%s: already suspended?\n", __func__);
goto done;
}
DBG(0, "%s: suspend root hub\n", __func__);
@@ -1839,7 +1840,7 @@ static int isp1362_bus_resume(struct usb_hcd *hcd)
isp1362_hcd->hc_control = isp1362_read_reg32(isp1362_hcd, HCCONTROL);
pr_info("%s: HCCONTROL: %08x\n", __func__, isp1362_hcd->hc_control);
if (hcd->state == HC_STATE_RESUMING) {
- pr_warning("%s: duplicate resume\n", __func__);
+ pr_warn("%s: duplicate resume\n", __func__);
status = 0;
} else
switch (isp1362_hcd->hc_control & OHCI_CTRL_HCFS) {
@@ -2474,8 +2475,8 @@ static int isp1362_chip_test(struct isp1362_hcd *isp1362_hcd)
__func__, offset);
break;
}
- pr_warning("%s: memory check with offset %02x ok after second read\n",
- __func__, offset);
+ pr_warn("%s: memory check with offset %02x ok after second read\n",
+ __func__, offset);
}
}
kfree(ref);
diff --git a/drivers/usb/isp1760/isp1760-if.c b/drivers/usb/isp1760/isp1760-if.c
index 9535b2872183..79205b31e4a9 100644
--- a/drivers/usb/isp1760/isp1760-if.c
+++ b/drivers/usb/isp1760/isp1760-if.c
@@ -197,7 +197,7 @@ static int isp1760_plat_probe(struct platform_device *pdev)
irq_res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
if (!irq_res) {
- pr_warning("isp1760: IRQ resource not available\n");
+ pr_warn("isp1760: IRQ resource not available\n");
return -ENODEV;
}
irqflags = irq_res->flags & IRQF_TRIGGER_MASK;
--
2.10.0.rc2.1.g053435c
^ permalink raw reply related
* ARM juno R2 board USB Issue (EHCI probe failed)
From: Hanjun Guo @ 2016-09-27 16:13 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <37a463cb-86d5-e0d7-7e8f-50cec3d65c95@arm.com>
On 09/27/2016 05:07 PM, Sudeep Holla wrote:
>
>
> On 27/09/16 09:55, Sajjan, Vikas C wrote:
>> Hi Sudeep,
>>
>> -----Original Message-----
>> From: Sudeep Holla [mailto:sudeep.holla at arm.com]
>> Sent: Tuesday, September 27, 2016 2:21 PM
>> To: Vikas Sajjan <sajjan.linux@gmail.com>; linux-usb at vger.kernel.org;
>> linux-arm-kernel at lists.infradead.org; linux-acpi at vger.kernel.org
>> Cc: Sudeep Holla <sudeep.holla@arm.com>; mark.rutland at arm.com;
>> lorenzo.pieralisi at arm.com; Sajjan, Vikas C <vikas.cha.sajjan@hpe.com>
>> Subject: Re: ARM juno R2 board USB Issue (EHCI probe failed)
>>
>> Hi Vikas,
>>
>> On 27/09/16 09:14, Vikas Sajjan wrote:
>>> Adding USB mailing list.
>>>
>>>
>>> On Tue, Sep 27, 2016 at 12:33 PM, Sajjan, Vikas C
>>> <vikas.cha.sajjan@hpe.com> wrote:
>>>> Hi All,
>>>>
>>>> I working on ARM juno R2 board, with latest kernel 4.8.rc7 and I get
>>>> below USB EHCI probe error while booting with acpi=force.
>>>>
>>
>> Are you using the latest UEFI EDK2 ?
>> No, I am still using the UEFI binary which came as part of the Juno
>> board.
>>
>>
>>>> [ 1.223662] VFIO - User Level meta-driver version: 0.3
>>>> [ 1.229335] ehci_hcd: USB 2.0 'Enhanced' Host Controller (EHCI)
>>>> Driver
>>>> [ 1.235882] ehci-pci: EHCI PCI platform driver
>>>> [ 1.240359] ehci-platform: EHCI generic platform driver
>>>> [ 1.245619] ehci-platform ARMH0D20:00: Error: DMA mask
>>>> configuration failed
>>>> [ 1.272491] ehci-platform: probe of ARMH0D20:00 failed with error -5
>>>> [ 1.278876] ohci_hcd: USB 1.1 'Open' Host Controller (OHCI) Driver
>>>> [ 1.285071] ohci-pci: OHCI PCI platform driver
>>>> [ 1.289548] ohci-platform: OHCI generic platform driver
>>>> [ 1.294884] usbcore: registered new interface driver usb-storage
>>>> [ 1.301231] mousedev: PS/2 mouse device common for all mice
>>>> [ 1.307197] rtc-efi rtc-efi: rtc core: registered rtc-efi as rtc0
>>>>
>>>> But this error goes off, if I don't force ACPI booting, i.e., if I
>>>> remove acpi=force from kernel command line , USB is detected and my
>>>> RFS which is in the usb drive, gets mounted successfully.
>>>>
>>
>> As I mentioned in private, I do get the same error if I drop _CCA in
>> USB object of ACPI DSDT. Can you give it a spin with latest UEFI ?
>>
>> Sure, will try with latest UEFI.
>>
>
> I bet that's 8-12 months old. It puts the banner during boot with the
> build date. You can try to follow [1] or access it from [2]
Agree.
D03 is using the same IP (EHCI) and the USB works fine with _CCA
in the device node.
Thanks
Hanjun
^ permalink raw reply
* [PATCH][v2] drm/sun4i: rgb: Enable panel after controller
From: Sean Paul @ 2016-09-27 16:05 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <20160926102146.19129-1-net147@gmail.com>
On Mon, Sep 26, 2016 at 6:21 AM, Jonathan Liu <net147@gmail.com> wrote:
> The panel should be enabled after the controller so that we do not have
> visual glitches on the panel while the controller is setup. Similarly,
> the panel should be disabled before the controller.
>
> Signed-off-by: Jonathan Liu <net147@gmail.com>
Cool, this makes much more sense.
Reviewed-by: Sean Paul <seanpaul@chromium.org>
I still think there's a problem with the bridge ops, though.
Sean
> ---
> Changes in v2:
> - Changed the commit message to be clearer
>
> drivers/gpu/drm/sun4i/sun4i_rgb.c | 14 ++++++++------
> 1 file changed, 8 insertions(+), 6 deletions(-)
>
> diff --git a/drivers/gpu/drm/sun4i/sun4i_rgb.c b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> index c3ff10f..4e4bea6 100644
> --- a/drivers/gpu/drm/sun4i/sun4i_rgb.c
> +++ b/drivers/gpu/drm/sun4i/sun4i_rgb.c
> @@ -152,15 +152,16 @@ static void sun4i_rgb_encoder_enable(struct drm_encoder *encoder)
>
> DRM_DEBUG_DRIVER("Enabling RGB output\n");
>
> - if (!IS_ERR(tcon->panel)) {
> + if (!IS_ERR(tcon->panel))
> drm_panel_prepare(tcon->panel);
> - drm_panel_enable(tcon->panel);
> - }
>
> /* encoder->bridge can be NULL; drm_bridge_enable checks for it */
> drm_bridge_enable(encoder->bridge);
>
> sun4i_tcon_channel_enable(tcon, 0);
> +
> + if (!IS_ERR(tcon->panel))
> + drm_panel_enable(tcon->panel);
> }
>
> static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
> @@ -171,15 +172,16 @@ static void sun4i_rgb_encoder_disable(struct drm_encoder *encoder)
>
> DRM_DEBUG_DRIVER("Disabling RGB output\n");
>
> + if (!IS_ERR(tcon->panel))
> + drm_panel_disable(tcon->panel);
> +
> sun4i_tcon_channel_disable(tcon, 0);
>
> /* encoder->bridge can be NULL; drm_bridge_disable checks for it */
> drm_bridge_disable(encoder->bridge);
>
> - if (!IS_ERR(tcon->panel)) {
> - drm_panel_disable(tcon->panel);
> + if (!IS_ERR(tcon->panel))
> drm_panel_unprepare(tcon->panel);
> - }
> }
>
> static void sun4i_rgb_encoder_mode_set(struct drm_encoder *encoder,
> --
> 2.10.0
>
^ permalink raw reply
* next-20160927 build: 2 failures 4 warnings (next-20160927)
From: Mark Brown @ 2016-09-27 16:00 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <E1bop0x-0001YK-4h@optimist>
On Tue, Sep 27, 2016 at 10:49:27AM +0100, Build bot for Mark Brown wrote:
-next is still failing to build an arm and arm64 allmodconfig due to:
> arm64-allmodconfig
> ERROR: "irq_set_parent" [drivers/mfd/tps65217.ko] undefined!
> arm-allmodconfig
> ERROR: "irq_set_parent" [drivers/mfd/tps65217.ko] undefined!
due to 262d5cc6ceb293 (mfd: tps65217: Add support for IRQs) since
irq_set_parent() isn't exported. There was a fix posted adding the
export to the IRQ subsystem but it's still not been applied, the
function is being used in order to enable lazy IRQ disabling for
threaded interrupts:
https://www.spinics.net/lists/arm-kernel/msg532864.html
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 455 bytes
Desc: not available
URL: <http://lists.infradead.org/pipermail/linux-arm-kernel/attachments/20160927/0a361488/attachment.sig>
^ permalink raw reply
* [PATCH] arm64: set path to Image.gz in the mkspec to avoid rpm build issue
From: Vadim Lomovtsev @ 2016-09-27 15:53 UTC (permalink / raw)
To: linux-arm-kernel
In addition to http://www.spinics.net/lists/arm-kernel/msg527466.html
While building rpm-pkg target it fails to copy kernel image
from default location to rpm buildroot directory.
Since we have arch variable set to aarch64 while Image.gz
is located at arch/arm64/boot it's necessary to specify
correct path to cp command as it implemeted for ppc64 build.
Signed-off-by: Vadim Lomovtsev <Vadim.Lomovtsev@caviumnetworks.com>
---
scripts/package/mkspec | 4 ++++
1 file changed, 4 insertions(+)
diff --git a/scripts/package/mkspec b/scripts/package/mkspec
index 57673ba..2f2bc7e 100755
--- a/scripts/package/mkspec
+++ b/scripts/package/mkspec
@@ -101,9 +101,13 @@ echo "%ifarch ppc64"
echo "cp vmlinux arch/powerpc/boot"
echo "cp arch/powerpc/boot/"'$KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
echo "%else"
+echo "%ifarch aarch64"
+echo "cp arch/arm64/boot/"'$KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
+echo "%else"
echo 'cp $KBUILD_IMAGE $RPM_BUILD_ROOT'"/boot/vmlinuz-$KERNELRELEASE"
echo "%endif"
echo "%endif"
+echo "%endif"
echo 'make %{?_smp_mflags} INSTALL_HDR_PATH=$RPM_BUILD_ROOT/usr KBUILD_SRC= headers_install'
echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE"
--
1.8.3.1
^ permalink raw reply related
* [PATCH v2 2/2] drm: zte: add initial vou drm driver
From: Sean Paul @ 2016-09-27 15:48 UTC (permalink / raw)
To: linux-arm-kernel
In-Reply-To: <1474727185-24180-3-git-send-email-shawn.guo@linaro.org>
On Sat, Sep 24, 2016 at 10:26 AM, Shawn Guo <shawn.guo@linaro.org> wrote:
> It adds the initial ZTE VOU display controller DRM driver. There are
> still some features to be added, like overlay plane, scaling, and more
> output devices support. But it's already useful with dual CRTCs and
> HDMI monitor working.
>
> It's been tested on Debian Jessie LXDE desktop with modesetting driver.
>
> Signed-off-by: Shawn Guo <shawn.guo@linaro.org>
Hi Shawn,
I think overall this is very well done! A couple of things stuck out
to me, I've pointed them out below, hopefully you can use some of
them.
Sean
> ---
> drivers/gpu/drm/Kconfig | 2 +
> drivers/gpu/drm/Makefile | 1 +
> drivers/gpu/drm/zte/Kconfig | 8 +
> drivers/gpu/drm/zte/Makefile | 8 +
> drivers/gpu/drm/zte/zx_crtc.c | 691 +++++++++++++++++++++++++++++++++++++++
> drivers/gpu/drm/zte/zx_crtc.h | 47 +++
> drivers/gpu/drm/zte/zx_drm_drv.c | 258 +++++++++++++++
> drivers/gpu/drm/zte/zx_drm_drv.h | 22 ++
> drivers/gpu/drm/zte/zx_hdmi.c | 540 ++++++++++++++++++++++++++++++
> drivers/gpu/drm/zte/zx_plane.c | 362 ++++++++++++++++++++
> drivers/gpu/drm/zte/zx_plane.h | 26 ++
> 11 files changed, 1965 insertions(+)
> create mode 100644 drivers/gpu/drm/zte/Kconfig
> create mode 100644 drivers/gpu/drm/zte/Makefile
> create mode 100644 drivers/gpu/drm/zte/zx_crtc.c
> create mode 100644 drivers/gpu/drm/zte/zx_crtc.h
> create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.c
> create mode 100644 drivers/gpu/drm/zte/zx_drm_drv.h
> create mode 100644 drivers/gpu/drm/zte/zx_hdmi.c
> create mode 100644 drivers/gpu/drm/zte/zx_plane.c
> create mode 100644 drivers/gpu/drm/zte/zx_plane.h
>
> diff --git a/drivers/gpu/drm/Kconfig b/drivers/gpu/drm/Kconfig
> index 483059a22b1b..a91f8cecbe0f 100644
> --- a/drivers/gpu/drm/Kconfig
> +++ b/drivers/gpu/drm/Kconfig
> @@ -223,6 +223,8 @@ source "drivers/gpu/drm/hisilicon/Kconfig"
>
> source "drivers/gpu/drm/mediatek/Kconfig"
>
> +source "drivers/gpu/drm/zte/Kconfig"
> +
> # Keep legacy drivers last
>
> menuconfig DRM_LEGACY
> diff --git a/drivers/gpu/drm/Makefile b/drivers/gpu/drm/Makefile
> index 439d89b25ae0..fe461c94d266 100644
> --- a/drivers/gpu/drm/Makefile
> +++ b/drivers/gpu/drm/Makefile
> @@ -85,3 +85,4 @@ obj-$(CONFIG_DRM_FSL_DCU) += fsl-dcu/
> obj-$(CONFIG_DRM_ETNAVIV) += etnaviv/
> obj-$(CONFIG_DRM_ARCPGU)+= arc/
> obj-y += hisilicon/
> +obj-$(CONFIG_DRM_ZTE) += zte/
> diff --git a/drivers/gpu/drm/zte/Kconfig b/drivers/gpu/drm/zte/Kconfig
> new file mode 100644
> index 000000000000..4065b2840f1c
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/Kconfig
> @@ -0,0 +1,8 @@
> +config DRM_ZTE
> + tristate "DRM Support for ZTE SoCs"
> + depends on DRM && ARCH_ZX
> + select DRM_KMS_CMA_HELPER
> + select DRM_KMS_FB_HELPER
> + select DRM_KMS_HELPER
> + help
> + Choose this option to enable DRM on ZTE ZX SoCs.
> diff --git a/drivers/gpu/drm/zte/Makefile b/drivers/gpu/drm/zte/Makefile
> new file mode 100644
> index 000000000000..b40968dc749f
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/Makefile
> @@ -0,0 +1,8 @@
> +zxdrm-y := \
> + zx_drm_drv.o \
> + zx_crtc.o \
> + zx_plane.o \
> + zx_hdmi.o
> +
> +obj-$(CONFIG_DRM_ZTE) += zxdrm.o
> +
> diff --git a/drivers/gpu/drm/zte/zx_crtc.c b/drivers/gpu/drm/zte/zx_crtc.c
I was a little tripped up when I first read this file since I assumed
there was one instance of this driver per-crtc. However, there's
really N crtcs per driver. Might it be less confusing to call it
zx_vou.c instead?
> new file mode 100644
> index 000000000000..818bf9072573
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_crtc.c
> @@ -0,0 +1,691 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * 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 <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_of.h>
> +#include <drm/drm_plane_helper.h>
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/of_address.h>
> +#include <video/videomode.h>
> +
> +#include "zx_drm_drv.h"
> +#include "zx_crtc.h"
> +#include "zx_plane.h"
> +
> +/* OSD (GPC_GLOBAL) registers */
> +#define OSD_INT_STA 0x04
> +#define OSD_INT_CLRSTA 0x08
> +#define OSD_INT_MSK 0x0c
> +#define OSD_INT_AUX_UPT BIT(14)
> +#define OSD_INT_MAIN_UPT BIT(13)
> +#define OSD_INT_GL1_LBW BIT(10)
> +#define OSD_INT_GL0_LBW BIT(9)
> +#define OSD_INT_VL2_LBW BIT(8)
> +#define OSD_INT_VL1_LBW BIT(7)
> +#define OSD_INT_VL0_LBW BIT(6)
> +#define OSD_INT_BUS_ERR BIT(3)
> +#define OSD_INT_CFG_ERR BIT(2)
> +#define OSD_INT_ERROR (\
> + OSD_INT_GL1_LBW | OSD_INT_GL0_LBW | \
> + OSD_INT_VL2_LBW | OSD_INT_VL1_LBW | OSD_INT_VL0_LBW | \
> + OSD_INT_BUS_ERR | OSD_INT_CFG_ERR \
> +)
> +#define OSD_INT_ENABLE (OSD_INT_ERROR | OSD_INT_AUX_UPT | OSD_INT_MAIN_UPT)
> +#define OSD_CTRL0 0x10
> +#define OSD_CTRL0_GL0_EN BIT(7)
> +#define OSD_CTRL0_GL0_SEL BIT(6)
> +#define OSD_CTRL0_GL1_EN BIT(5)
> +#define OSD_CTRL0_GL1_SEL BIT(4)
> +#define OSD_RST_CLR 0x1c
> +#define RST_PER_FRAME BIT(19)
> +
> +/* Main/Aux channel registers */
> +#define OSD_MAIN_CHN 0x470
> +#define OSD_AUX_CHN 0x4d0
> +#define CHN_CTRL0 0x00
> +#define CHN_ENABLE BIT(0)
> +#define CHN_CTRL1 0x04
> +#define CHN_SCREEN_W_SHIFT 18
> +#define CHN_SCREEN_W_MASK (0x1fff << CHN_SCREEN_W_SHIFT)
> +#define CHN_SCREEN_H_SHIFT 5
> +#define CHN_SCREEN_H_MASK (0x1fff << CHN_SCREEN_H_SHIFT)
> +#define CHN_UPDATE 0x08
> +
> +/* TIMING_CTRL registers */
> +#define TIMING_TC_ENABLE 0x04
> +#define AUX_TC_EN BIT(1)
> +#define MAIN_TC_EN BIT(0)
> +#define FIR_MAIN_ACTIVE 0x08
> +#define FIR_AUX_ACTIVE 0x0c
> +#define FIR_MAIN_H_TIMING 0x10
> +#define FIR_MAIN_V_TIMING 0x14
> +#define FIR_AUX_H_TIMING 0x18
> +#define FIR_AUX_V_TIMING 0x1c
> +#define SYNC_WIDE_SHIFT 22
> +#define SYNC_WIDE_MASK (0x3ff << SYNC_WIDE_SHIFT)
> +#define BACK_PORCH_SHIFT 11
> +#define BACK_PORCH_MASK (0x7ff << BACK_PORCH_SHIFT)
> +#define FRONT_PORCH_SHIFT 0
> +#define FRONT_PORCH_MASK (0x7ff << FRONT_PORCH_SHIFT)
> +#define TIMING_CTRL 0x20
> +#define AUX_POL_SHIFT 3
> +#define AUX_POL_MASK (0x7 << AUX_POL_SHIFT)
> +#define MAIN_POL_SHIFT 0
> +#define MAIN_POL_MASK (0x7 << MAIN_POL_SHIFT)
> +#define POL_DE_SHIFT 2
> +#define POL_VSYNC_SHIFT 1
> +#define POL_HSYNC_SHIFT 0
> +#define TIMING_INT_CTRL 0x24
> +#define TIMING_INT_STATE 0x28
> +#define TIMING_INT_AUX_FRAME BIT(3)
> +#define TIMING_INT_MAIN_FRAME BIT(1)
> +#define TIMING_INT_AUX_FRAME_SEL_VSW (0x2 << 10)
> +#define TIMING_INT_MAIN_FRAME_SEL_VSW (0x2 << 6)
> +#define TIMING_INT_ENABLE (\
> + TIMING_INT_MAIN_FRAME_SEL_VSW | TIMING_INT_AUX_FRAME_SEL_VSW | \
> + TIMING_INT_MAIN_FRAME | TIMING_INT_AUX_FRAME \
> +)
> +#define TIMING_MAIN_SHIFT 0x2c
> +#define TIMING_AUX_SHIFT 0x30
> +#define H_SHIFT_VAL 0x0048
> +#define TIMING_MAIN_PI_SHIFT 0x68
> +#define TIMING_AUX_PI_SHIFT 0x6c
> +#define H_PI_SHIFT_VAL 0x000f
> +
> +/* DTRC registers */
> +#define DTRC_F0_CTRL 0x2c
> +#define DTRC_F1_CTRL 0x5c
> +#define DTRC_DECOMPRESS_BYPASS BIT(17)
> +#define DTRC_DETILE_CTRL 0x68
> +#define TILE2RASTESCAN_BYPASS_MODE BIT(30)
> +#define DETILE_ARIDR_MODE_MASK (0x3 << 0)
> +#define DETILE_ARID_ALL 0
> +#define DETILE_ARID_IN_ARIDR 1
> +#define DETILE_ARID_BYP_BUT_ARIDR 2
> +#define DETILE_ARID_IN_ARIDR2 3
> +#define DTRC_ARID 0x6c
> +#define DTRC_DEC2DDR_ARID 0x70
> +
> +/* VOU_CTRL registers */
> +#define VOU_INF_EN 0x00
> +#define VOU_INF_CH_SEL 0x04
> +#define VOU_INF_DATA_SEL 0x08
> +#define VOU_SOFT_RST 0x14
> +#define VOU_CLK_SEL 0x18
> +#define VOU_CLK_GL1_SEL BIT(5)
> +#define VOU_CLK_GL0_SEL BIT(4)
> +#define VOU_CLK_REQEN 0x20
> +#define VOU_CLK_EN 0x24
> +
> +/* OTFPPU_CTRL registers */
> +#define OTFPPU_RSZ_DATA_SOURCE 0x04
> +
> +#define GL_NUM 2
> +#define VL_NUM 3
> +
> +enum vou_chn_type {
> + VOU_CHN_MAIN,
> + VOU_CHN_AUX,
> +};
> +
> +struct zx_crtc {
> + struct drm_crtc crtc;
> + struct drm_plane *primary;
> + struct device *dev;
> + void __iomem *chnreg;
> + enum vou_chn_type chn_type;
> + struct clk *pixclk;
> +};
> +
> +#define to_zx_crtc(x) container_of(crtc, struct zx_crtc, crtc)
> +
> +struct zx_vou_hw {
> + struct device *dev;
> + void __iomem *osd;
> + void __iomem *timing;
> + void __iomem *vouctl;
> + void __iomem *otfppu;
> + void __iomem *dtrc;
> + struct clk *axi_clk;
> + struct clk *ppu_clk;
> + struct clk *main_clk;
> + struct clk *aux_clk;
> + struct zx_crtc *main_crtc;
> + struct zx_crtc *aux_crtc;
> +};
> +
> +static inline bool is_main_crtc(struct drm_crtc *crtc)
> +{
> + struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> +
> + return zcrtc->chn_type == VOU_CHN_MAIN;
> +}
> +
> +void vou_inf_enable(struct vou_inf *inf)
> +{
> + struct drm_encoder *encoder = inf->encoder;
> + struct drm_device *drm = encoder->dev;
> + struct zx_drm_private *priv = drm->dev_private;
> + struct zx_vou_hw *vou = priv->vou;
> + bool is_main = is_main_crtc(encoder->crtc);
> + u32 data_sel_shift = inf->id << 1;
> + u32 val;
> +
> + /* Select data format */
> + val = readl(vou->vouctl + VOU_INF_DATA_SEL);
> + val &= ~(0x3 << data_sel_shift);
> + val |= inf->data_sel << data_sel_shift;
> + writel(val, vou->vouctl + VOU_INF_DATA_SEL);
> +
> + /* Select channel */
> + val = readl(vou->vouctl + VOU_INF_CH_SEL);
> + if (is_main)
> + val &= ~(1 << inf->id);
> + else
> + val |= 1 << inf->id;
> + writel(val, vou->vouctl + VOU_INF_CH_SEL);
> +
> + /* Select interface clocks */
> + val = readl(vou->vouctl + VOU_CLK_SEL);
> + if (is_main)
> + val &= ~inf->clocks_sel_bits;
> + else
> + val |= inf->clocks_sel_bits;
> + writel(val, vou->vouctl + VOU_CLK_SEL);
> +
> + /* Enable interface clocks */
> + val = readl(vou->vouctl + VOU_CLK_EN);
> + val |= inf->clocks_en_bits;
> + writel(val, vou->vouctl + VOU_CLK_EN);
> +
> + /* Enable the device */
> + val = readl(vou->vouctl + VOU_INF_EN);
> + val |= 1 << inf->id;
> + writel(val, vou->vouctl + VOU_INF_EN);
> +}
> +
> +void vou_inf_disable(struct vou_inf *inf)
> +{
> + struct drm_encoder *encoder = inf->encoder;
> + struct drm_device *drm = encoder->dev;
> + struct zx_drm_private *priv = drm->dev_private;
> + struct zx_vou_hw *vou = priv->vou;
> + u32 val;
> +
> + /* Disable the device */
> + val = readl(vou->vouctl + VOU_INF_EN);
> + val &= ~(1 << inf->id);
> + writel(val, vou->vouctl + VOU_INF_EN);
> +
> + /* Disable interface clocks */
> + val = readl(vou->vouctl + VOU_CLK_EN);
> + val &= ~inf->clocks_en_bits;
> + writel(val, vou->vouctl + VOU_CLK_EN);
> +}
> +
> +static inline void vou_chn_set_update(struct zx_crtc *zcrtc)
> +{
> + writel(1, zcrtc->chnreg + CHN_UPDATE);
> +}
> +
> +static void zx_crtc_enable(struct drm_crtc *crtc)
> +{
> + struct drm_display_mode *mode = &crtc->state->adjusted_mode;
> + struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> + struct zx_vou_hw *vou = dev_get_drvdata(zcrtc->dev);
IMO, it would be better to store a pointer to vou in each zx_crtc
rather than reaching into drvdata.
> + bool is_main = is_main_crtc(crtc);
> + struct videomode vm;
> + u32 pol = 0;
> + u32 val;
> +
> + drm_display_mode_to_videomode(mode, &vm);
Why do this conversion? You should be able to get everything you need
from drm_display_mode
> +
> + /* Set up timing parameters */
> + val = (vm.vactive - 1) << 16;
> + val |= (vm.hactive - 1) & 0xffff;
> + writel(val, vou->timing + (is_main ? FIR_MAIN_ACTIVE : FIR_AUX_ACTIVE));
> +
> + val = ((vm.hsync_len - 1) << SYNC_WIDE_SHIFT) & SYNC_WIDE_MASK;
> + val |= ((vm.hback_porch - 1) << BACK_PORCH_SHIFT) & BACK_PORCH_MASK;
> + val |= ((vm.hfront_porch - 1) << FRONT_PORCH_SHIFT) & FRONT_PORCH_MASK;
> + writel(val, vou->timing + (is_main ? FIR_MAIN_H_TIMING :
> + FIR_AUX_H_TIMING));
> +
> + val = ((vm.vsync_len - 1) << SYNC_WIDE_SHIFT) & SYNC_WIDE_MASK;
> + val |= ((vm.vback_porch - 1) << BACK_PORCH_SHIFT) & BACK_PORCH_MASK;
> + val |= ((vm.vfront_porch - 1) << FRONT_PORCH_SHIFT) & FRONT_PORCH_MASK;
> + writel(val, vou->timing + (is_main ? FIR_MAIN_V_TIMING :
> + FIR_AUX_V_TIMING));
It would be nice to figure out a better way of handing the main/aux
switch as opposed to sprinkling all of these inline conditionals
around. Perhaps you could introduce a struct which stores the
addresses per-crtc and then reference the struct in the driver as
opposed to the #defines.
ie:
writel(val, vou->timing + zcrtc->regs->v_timing);
> +
> + /* Set up polarities */
> + if (vm.flags & DISPLAY_FLAGS_VSYNC_LOW)
> + pol |= 1 << POL_VSYNC_SHIFT;
> + if (vm.flags & DISPLAY_FLAGS_HSYNC_LOW)
> + pol |= 1 << POL_HSYNC_SHIFT;
> +
> + val = readl(vou->timing + TIMING_CTRL);
> + val &= ~(is_main ? MAIN_POL_MASK : AUX_POL_MASK);
> + val |= pol << (is_main ? MAIN_POL_SHIFT : AUX_POL_SHIFT);
> + writel(val, vou->timing + TIMING_CTRL);
> +
> + /* Setup SHIFT register by following what ZTE BSP does */
> + writel(H_SHIFT_VAL, vou->timing + (is_main ? TIMING_MAIN_SHIFT :
> + TIMING_AUX_SHIFT));
> + writel(H_PI_SHIFT_VAL, vou->timing + (is_main ? TIMING_MAIN_PI_SHIFT :
> + TIMING_AUX_PI_SHIFT));
> +
> + /* Enable TIMING_CTRL */
> + val = readl(vou->timing + TIMING_TC_ENABLE);
> + val |= is_main ? MAIN_TC_EN : AUX_TC_EN;
> + writel(val, vou->timing + TIMING_TC_ENABLE);
> +
> + /* Configure channel screen size */
> + val = readl(zcrtc->chnreg + CHN_CTRL1);
> + val &= ~(CHN_SCREEN_W_MASK | CHN_SCREEN_H_MASK);
> + val |= (vm.hactive << CHN_SCREEN_W_SHIFT) & CHN_SCREEN_W_MASK;
> + val |= (vm.vactive << CHN_SCREEN_H_SHIFT) & CHN_SCREEN_H_MASK;
> + writel(val, zcrtc->chnreg + CHN_CTRL1);
> +
> + /* Update channel */
> + vou_chn_set_update(zcrtc);
> +
> + /* Enable channel */
> + val = readl(zcrtc->chnreg + CHN_CTRL0);
> + val |= CHN_ENABLE;
> + writel(val, zcrtc->chnreg + CHN_CTRL0);
> +
> + /* Enable Graphic Layer */
> + val = readl(vou->osd + OSD_CTRL0);
> + val |= is_main ? OSD_CTRL0_GL0_EN : OSD_CTRL0_GL1_EN;
> + writel(val, vou->osd + OSD_CTRL0);
> +
> + drm_crtc_vblank_on(crtc);
> +
> + /* Enable pixel clock */
> + clk_set_rate(zcrtc->pixclk, mode->clock * 1000);
> + clk_prepare_enable(zcrtc->pixclk);
> +}
> +
> +static void zx_crtc_disable(struct drm_crtc *crtc)
> +{
> + struct zx_crtc *zcrtc = to_zx_crtc(crtc);
> + struct zx_vou_hw *vou = dev_get_drvdata(zcrtc->dev);
> + bool is_main = is_main_crtc(crtc);
> + u32 val;
> +
> + clk_disable_unprepare(zcrtc->pixclk);
> +
> + drm_crtc_vblank_off(crtc);
> +
> + /* Disable Graphic Layer */
> + val = readl(vou->osd + OSD_CTRL0);
> + val &= ~(is_main ? OSD_CTRL0_GL0_EN : OSD_CTRL0_GL1_EN);
> + writel(val, vou->osd + OSD_CTRL0);
> +
> + /* Disable channel */
> + val = readl(zcrtc->chnreg + CHN_CTRL0);
> + val &= ~CHN_ENABLE;
> + writel(val, zcrtc->chnreg + CHN_CTRL0);
> +
> + /* Disable TIMING_CTRL */
> + val = readl(vou->timing + TIMING_TC_ENABLE);
> + val &= ~(is_main ? MAIN_TC_EN : AUX_TC_EN);
> + writel(val, vou->timing + TIMING_TC_ENABLE);
> +}
> +
> +static void zx_crtc_atomic_begin(struct drm_crtc *crtc,
> + struct drm_crtc_state *state)
> +{
> + struct drm_pending_vblank_event *event = crtc->state->event;
> +
> + if (event) {
nit: you can save yourself a level of indentation by exiting early on
!event instead of scoping the entire function on event.
> + crtc->state->event = NULL;
> +
> + spin_lock_irq(&crtc->dev->event_lock);
> + if (drm_crtc_vblank_get(crtc) == 0)
> + drm_crtc_arm_vblank_event(crtc, event);
> + else
> + drm_crtc_send_vblank_event(crtc, event);
> + spin_unlock_irq(&crtc->dev->event_lock);
> + }
> +}
> +
> +static const struct drm_crtc_helper_funcs zx_crtc_helper_funcs = {
> + .enable = zx_crtc_enable,
> + .disable = zx_crtc_disable,
> + .atomic_begin = zx_crtc_atomic_begin,
> +};
> +
> +static const struct drm_crtc_funcs zx_crtc_funcs = {
> + .destroy = drm_crtc_cleanup,
> + .set_config = drm_atomic_helper_set_config,
> + .page_flip = drm_atomic_helper_page_flip,
> + .reset = drm_atomic_helper_crtc_reset,
> + .atomic_duplicate_state = drm_atomic_helper_crtc_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_crtc_destroy_state,
> +};
> +
> +static struct zx_crtc *zx_crtc_init(struct drm_device *drm,
> + enum vou_chn_type chn_type)
> +{
> + struct zx_drm_private *priv = drm->dev_private;
> + struct zx_vou_hw *vou = priv->vou;
> + struct device *dev = vou->dev;
> + struct zx_layer_data data;
> + struct zx_crtc *zcrtc;
> + int ret;
> +
> + zcrtc = devm_kzalloc(dev, sizeof(*zcrtc), GFP_KERNEL);
> + if (!zcrtc)
> + return ERR_PTR(-ENOMEM);
> +
> + zcrtc->dev = dev;
> + zcrtc->chn_type = chn_type;
> +
> + if (chn_type == VOU_CHN_MAIN) {
> + data.layer = vou->osd + 0x130;
> + data.csc = vou->osd + 0x580;
> + data.hbsc = vou->osd + 0x820;
> + data.rsz = vou->otfppu + 0x600;
> + zcrtc->chnreg = vou->osd + OSD_MAIN_CHN;
> + } else {
> + data.layer = vou->osd + 0x200;
> + data.csc = vou->osd + 0x5d0;
> + data.hbsc = vou->osd + 0x860;
> + data.rsz = vou->otfppu + 0x800;
> + zcrtc->chnreg = vou->osd + OSD_AUX_CHN;
> + }
These magic values should find their way into #defines
> +
> + zcrtc->pixclk = devm_clk_get(dev, (chn_type == VOU_CHN_MAIN) ?
> + "main_wclk" : "aux_wclk");
> + if (IS_ERR(zcrtc->pixclk))
> + return ERR_PTR(PTR_ERR(zcrtc->pixclk));
> +
> + zcrtc->primary = zx_plane_init(drm, dev, &data, DRM_PLANE_TYPE_PRIMARY);
> + if (IS_ERR(zcrtc->primary))
> + return ERR_PTR(PTR_ERR(zcrtc->primary));
> +
> + ret = drm_crtc_init_with_planes(drm, &zcrtc->crtc, zcrtc->primary, NULL,
> + &zx_crtc_funcs, NULL);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + drm_crtc_helper_add(&zcrtc->crtc, &zx_crtc_helper_funcs);
> +
> + return zcrtc;
> +}
> +
> +int zx_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe)
> +{
> + struct zx_drm_private *priv = drm->dev_private;
> + struct zx_vou_hw *vou = priv->vou;
> + u32 intctl;
> +
> + intctl = readl(vou->timing + TIMING_INT_CTRL);
> + if (pipe == 0)
> + intctl |= TIMING_INT_MAIN_FRAME;
> + else
> + intctl |= TIMING_INT_AUX_FRAME;
> + writel(intctl, vou->timing + TIMING_INT_CTRL);
> +
> + return 0;
> +}
> +
> +void zx_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe)
> +{
> + struct zx_drm_private *priv = drm->dev_private;
> + struct zx_vou_hw *vou = priv->vou;
> + u32 intctl;
> +
> + intctl = readl(vou->timing + TIMING_INT_CTRL);
> + if (pipe == 0)
> + intctl &= ~TIMING_INT_MAIN_FRAME;
> + else
> + intctl &= ~TIMING_INT_AUX_FRAME;
> + writel(intctl, vou->timing + TIMING_INT_CTRL);
> +}
> +
> +static irqreturn_t vou_irq_handler(int irq, void *dev_id)
> +{
> + struct zx_vou_hw *vou = dev_id;
> + u32 state;
> +
> + /* Handle TIMING_CTRL frame interrupts */
> + state = readl(vou->timing + TIMING_INT_STATE);
> + writel(state, vou->timing + TIMING_INT_STATE);
> +
> + if (state & TIMING_INT_MAIN_FRAME)
> + drm_crtc_handle_vblank(&vou->main_crtc->crtc);
> +
> + if (state & TIMING_INT_AUX_FRAME)
> + drm_crtc_handle_vblank(&vou->aux_crtc->crtc);
> +
> + /* Handle OSD interrupts */
> + state = readl(vou->osd + OSD_INT_STA);
> + writel(state, vou->osd + OSD_INT_CLRSTA);
> +
> + if (state & OSD_INT_MAIN_UPT) {
> + vou_chn_set_update(vou->main_crtc);
> + zx_plane_set_update(vou->main_crtc->primary);
> + }
> +
> + if (state & OSD_INT_AUX_UPT) {
> + vou_chn_set_update(vou->aux_crtc);
> + zx_plane_set_update(vou->aux_crtc->primary);
> + }
> +
> + if (state & OSD_INT_ERROR)
> + dev_err(vou->dev, "OSD ERROR: 0x%08x!\n", state);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static void vou_dtrc_init(struct zx_vou_hw *vou)
> +{
> + u32 val;
> +
> + val = readl(vou->dtrc + DTRC_DETILE_CTRL);
> + /* Clear bit for bypass by ID */
> + val &= ~TILE2RASTESCAN_BYPASS_MODE;
> + /* Select ARIDR mode */
> + val &= ~DETILE_ARIDR_MODE_MASK;
> + val |= DETILE_ARID_IN_ARIDR;
> + writel(val, vou->dtrc + DTRC_DETILE_CTRL);
> +
> + /* Bypass decompression for both frames */
> + val = readl(vou->dtrc + DTRC_F0_CTRL);
> + val |= DTRC_DECOMPRESS_BYPASS;
> + writel(val, vou->dtrc + DTRC_F0_CTRL);
> +
> + val = readl(vou->dtrc + DTRC_F1_CTRL);
> + val |= DTRC_DECOMPRESS_BYPASS;
> + writel(val, vou->dtrc + DTRC_F1_CTRL);
> +
> + /* Set up ARID register */
> + val = 0x0e;
> + val |= 0x0f << 8;
> + val |= 0x0e << 16;
> + val |= 0x0f << 24;
#define
> + writel(val, vou->dtrc + DTRC_ARID);
> +
> + /* Set up DEC2DDR_ARID register */
> + val = 0x0e;
> + val |= 0x0f << 8;
> + writel(val, vou->dtrc + DTRC_DEC2DDR_ARID);
> +}
> +
> +static void vou_hw_init(struct zx_vou_hw *vou)
> +{
> + u32 val;
> +
> + /* Set GL0 to main channel and GL1 to aux channel */
> + val = readl(vou->osd + OSD_CTRL0);
> + val &= ~OSD_CTRL0_GL0_SEL;
> + val |= OSD_CTRL0_GL1_SEL;
> + writel(val, vou->osd + OSD_CTRL0);
> +
> + /* Release reset for all VOU modules */
> + writel(~0, vou->vouctl + VOU_SOFT_RST);
> +
> + /* Select main clock for GL0 and aux clock for GL1 module */
> + val = readl(vou->vouctl + VOU_CLK_SEL);
> + val &= ~VOU_CLK_GL0_SEL;
> + val |= VOU_CLK_GL1_SEL;
> + writel(val, vou->vouctl + VOU_CLK_SEL);
> +
> + /* Enable clock auto-gating for all VOU modules */
> + writel(~0, vou->vouctl + VOU_CLK_REQEN);
> +
> + /* Enable all VOU module clocks */
> + writel(~0, vou->vouctl + VOU_CLK_EN);
> +
> + /* Clear both OSD and TIMING_CTRL interrupt state */
> + writel(~0, vou->osd + OSD_INT_CLRSTA);
> + writel(~0, vou->timing + TIMING_INT_STATE);
> +
> + /* Enable OSD and TIMING_CTRL interrrupts */
> + writel(OSD_INT_ENABLE, vou->osd + OSD_INT_MSK);
> + writel(TIMING_INT_ENABLE, vou->timing + TIMING_INT_CTRL);
> +
> + /* Select GPC as input to gl/vl scaler as a sane default setting */
> + writel(0x2a, vou->otfppu + OTFPPU_RSZ_DATA_SOURCE);
> +
> + /*
> + * Needs to reset channel and layer logic per frame when frame starts
> + * to get VOU work properly.
> + */
> + val = readl(vou->osd + OSD_RST_CLR);
> + val |= RST_PER_FRAME;
> + writel(val, vou->osd + OSD_RST_CLR);
> +
> + vou_dtrc_init(vou);
> +}
> +
> +static int zx_crtc_bind(struct device *dev, struct device *master, void *data)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct drm_device *drm = data;
> + struct zx_drm_private *priv = drm->dev_private;
> + struct resource *res;
> + struct zx_vou_hw *vou;
> + int irq;
> + int ret;
> +
> + vou = devm_kzalloc(dev, sizeof(*vou), GFP_KERNEL);
> + if (!vou)
> + return -ENOMEM;
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "osd");
> + vou->osd = devm_ioremap_resource(dev, res);
> + if (IS_ERR(vou->osd))
> + return PTR_ERR(vou->osd);
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "timing_ctrl");
> + vou->timing = devm_ioremap_resource(dev, res);
> + if (IS_ERR(vou->timing))
> + return PTR_ERR(vou->timing);
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "dtrc");
> + vou->dtrc = devm_ioremap_resource(dev, res);
> + if (IS_ERR(vou->dtrc))
> + return PTR_ERR(vou->dtrc);
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "vou_ctrl");
> + vou->vouctl = devm_ioremap_resource(dev, res);
> + if (IS_ERR(vou->vouctl))
> + return PTR_ERR(vou->vouctl);
> +
> + res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "otfppu");
> + vou->otfppu = devm_ioremap_resource(dev, res);
> + if (IS_ERR(vou->otfppu))
> + return PTR_ERR(vou->otfppu);
> +
> + irq = platform_get_irq(pdev, 0);
> + if (irq < 0)
> + return irq;
> +
> + vou->axi_clk = devm_clk_get(dev, "aclk");
> + if (IS_ERR(vou->axi_clk))
> + return PTR_ERR(vou->axi_clk);
> +
> + vou->ppu_clk = devm_clk_get(dev, "ppu_wclk");
> + if (IS_ERR(vou->ppu_clk))
> + return PTR_ERR(vou->ppu_clk);
> +
> + clk_prepare_enable(vou->axi_clk);
> + clk_prepare_enable(vou->ppu_clk);
> +
> + vou->dev = dev;
> + priv->vou = vou;
> + dev_set_drvdata(dev, vou);
I think you should be able to avoid storing vou in priv and drvdata.
> +
> + vou_hw_init(vou);
> +
> + ret = devm_request_irq(dev, irq, vou_irq_handler, 0, "zx_vou", vou);
> + if (ret < 0)
> + return ret;
> +
> + vou->main_crtc = zx_crtc_init(drm, VOU_CHN_MAIN);
> + if (IS_ERR(vou->main_crtc))
> + return PTR_ERR(vou->main_crtc);
> +
> + vou->aux_crtc = zx_crtc_init(drm, VOU_CHN_AUX);
> + if (IS_ERR(vou->aux_crtc))
> + return PTR_ERR(vou->aux_crtc);
> +
> + return 0;
> +}
> +
> +static void zx_crtc_unbind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct zx_vou_hw *vou = dev_get_drvdata(dev);
> +
> + clk_disable_unprepare(vou->axi_clk);
> + clk_disable_unprepare(vou->ppu_clk);
> +}
> +
> +static const struct component_ops zx_crtc_component_ops = {
> + .bind = zx_crtc_bind,
> + .unbind = zx_crtc_unbind,
> +};
> +
> +static int zx_crtc_probe(struct platform_device *pdev)
> +{
> + return component_add(&pdev->dev, &zx_crtc_component_ops);
> +}
> +
> +static int zx_crtc_remove(struct platform_device *pdev)
> +{
> + component_del(&pdev->dev, &zx_crtc_component_ops);
> + return 0;
> +}
> +
> +static const struct of_device_id zx_crtc_of_match[] = {
> + { .compatible = "zte,zx296718-dpc", },
> + { /* end */ },
> +};
> +MODULE_DEVICE_TABLE(of, zx_crtc_of_match);
> +
> +struct platform_driver zx_crtc_driver = {
> + .probe = zx_crtc_probe,
> + .remove = zx_crtc_remove,
> + .driver = {
> + .name = "zx-crtc",
> + .of_match_table = zx_crtc_of_match,
> + },
> +};
> diff --git a/drivers/gpu/drm/zte/zx_crtc.h b/drivers/gpu/drm/zte/zx_crtc.h
> new file mode 100644
> index 000000000000..f889208054ce
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_crtc.h
> @@ -0,0 +1,47 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * 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 __ZX_CRTC_H__
> +#define __ZX_CRTC_H__
> +
> +#define VOU_CRTC_MASK 0x3
> +
> +/* VOU output interfaces */
> +enum vou_inf_id {
> + VOU_HDMI = 0,
> + VOU_RGB_LCD = 1,
> + VOU_TV_ENC = 2,
> + VOU_MIPI_DSI = 3,
> + VOU_LVDS = 4,
> + VOU_VGA = 5,
> +};
> +
> +enum vou_inf_data_sel {
> + VOU_YUV444 = 0,
> + VOU_RGB_101010 = 1,
> + VOU_RGB_888 = 2,
> + VOU_RGB_666 = 3,
> +};
> +
> +struct vou_inf {
> + struct drm_encoder *encoder;
> + enum vou_inf_id id;
> + enum vou_inf_data_sel data_sel;
> + u32 clocks_en_bits;
> + u32 clocks_sel_bits;
> +};
> +
> +void vou_inf_enable(struct vou_inf *inf);
> +void vou_inf_disable(struct vou_inf *inf);
> +
> +int zx_crtc_enable_vblank(struct drm_device *drm, unsigned int pipe);
> +void zx_crtc_disable_vblank(struct drm_device *drm, unsigned int pipe);
> +
> +#endif /* __ZX_CRTC_H__ */
> diff --git a/drivers/gpu/drm/zte/zx_drm_drv.c b/drivers/gpu/drm/zte/zx_drm_drv.c
> new file mode 100644
> index 000000000000..51fafb8e5f43
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_drm_drv.c
> @@ -0,0 +1,258 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * 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/spinlock.h>
> +#include <linux/clk.h>
> +#include <linux/component.h>
> +#include <linux/list.h>
> +#include <linux/of_graph.h>
> +#include <linux/of_platform.h>
nit: Alphabetical?
> +
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_fb_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_of.h>
> +
> +#include "zx_drm_drv.h"
> +#include "zx_crtc.h"
> +
> +static void zx_drm_fb_output_poll_changed(struct drm_device *drm)
> +{
> + struct zx_drm_private *priv = drm->dev_private;
> +
> + drm_fbdev_cma_hotplug_event(priv->fbdev);
> +}
> +
> +static const struct drm_mode_config_funcs zx_drm_mode_config_funcs = {
> + .fb_create = drm_fb_cma_create,
> + .output_poll_changed = zx_drm_fb_output_poll_changed,
> + .atomic_check = drm_atomic_helper_check,
> + .atomic_commit = drm_atomic_helper_commit,
> +};
> +
> +static void zx_drm_lastclose(struct drm_device *drm)
> +{
> + struct zx_drm_private *priv = drm->dev_private;
> +
> + drm_fbdev_cma_restore_mode(priv->fbdev);
> +}
> +
> +static const struct file_operations zx_drm_fops = {
> + .owner = THIS_MODULE,
> + .open = drm_open,
> + .release = drm_release,
> + .unlocked_ioctl = drm_ioctl,
> +#ifdef CONFIG_COMPAT
> + .compat_ioctl = drm_compat_ioctl,
> +#endif
> + .poll = drm_poll,
> + .read = drm_read,
> + .llseek = noop_llseek,
> + .mmap = drm_gem_cma_mmap,
> +};
> +
> +static struct drm_driver zx_drm_driver = {
> + .driver_features = DRIVER_GEM | DRIVER_MODESET | DRIVER_PRIME |
> + DRIVER_ATOMIC,
> + .lastclose = zx_drm_lastclose,
> + .get_vblank_counter = drm_vblank_no_hw_counter,
> + .enable_vblank = zx_crtc_enable_vblank,
> + .disable_vblank = zx_crtc_disable_vblank,
> + .gem_free_object = drm_gem_cma_free_object,
> + .gem_vm_ops = &drm_gem_cma_vm_ops,
> + .dumb_create = drm_gem_cma_dumb_create,
> + .dumb_map_offset = drm_gem_cma_dumb_map_offset,
> + .dumb_destroy = drm_gem_dumb_destroy,
> + .prime_handle_to_fd = drm_gem_prime_handle_to_fd,
> + .prime_fd_to_handle = drm_gem_prime_fd_to_handle,
> + .gem_prime_export = drm_gem_prime_export,
> + .gem_prime_import = drm_gem_prime_import,
> + .gem_prime_get_sg_table = drm_gem_cma_prime_get_sg_table,
> + .gem_prime_import_sg_table = drm_gem_cma_prime_import_sg_table,
> + .gem_prime_vmap = drm_gem_cma_prime_vmap,
> + .gem_prime_vunmap = drm_gem_cma_prime_vunmap,
> + .gem_prime_mmap = drm_gem_cma_prime_mmap,
> + .fops = &zx_drm_fops,
> + .name = "zx-vou",
> + .desc = "ZTE VOU Controller DRM",
> + .date = "20160811",
> + .major = 1,
> + .minor = 0,
> +};
> +
> +static int zx_drm_bind(struct device *dev)
> +{
> + struct drm_device *drm;
> + struct zx_drm_private *priv;
> + int ret;
> +
> + priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
> + if (!priv)
> + return -ENOMEM;
> +
> + drm = drm_dev_alloc(&zx_drm_driver, dev);
> + if (!drm)
> + return -ENOMEM;
> +
> + drm->dev_private = priv;
> + dev_set_drvdata(dev, drm);
> +
> + drm_mode_config_init(drm);
> + drm->mode_config.min_width = 16;
> + drm->mode_config.min_height = 16;
> + drm->mode_config.max_width = 4096;
> + drm->mode_config.max_height = 4096;
> + drm->mode_config.funcs = &zx_drm_mode_config_funcs;
> +
> + ret = drm_dev_register(drm, 0);
> + if (ret)
> + goto out_free;
> +
> + ret = component_bind_all(dev, drm);
> + if (ret) {
> + DRM_ERROR("Failed to bind all components\n");
> + goto out_unregister;
> + }
> +
> + ret = drm_vblank_init(drm, drm->mode_config.num_crtc);
> + if (ret < 0) {
> + DRM_ERROR("failed to initialise vblank\n");
> + goto out_unbind;
> + }
> +
> + /*
> + * We will manage irq handler on our own. In this case, irq_enabled
> + * need to be true for using vblank core support.
> + */
> + drm->irq_enabled = true;
> +
> + drm_mode_config_reset(drm);
> + drm_kms_helper_poll_init(drm);
> +
> + priv->fbdev = drm_fbdev_cma_init(drm, 32, drm->mode_config.num_crtc,
> + drm->mode_config.num_connector);
> + if (IS_ERR(priv->fbdev)) {
> + ret = PTR_ERR(priv->fbdev);
> + priv->fbdev = NULL;
> + goto out_fini;
> + }
> +
> + return 0;
> +
> +out_fini:
> + drm_kms_helper_poll_fini(drm);
> + drm_mode_config_cleanup(drm);
> + drm_vblank_cleanup(drm);
> +out_unbind:
> + component_unbind_all(dev, drm);
> +out_unregister:
> + drm_dev_unregister(drm);
> +out_free:
> + dev_set_drvdata(dev, NULL);
> + drm_dev_unref(drm);
> + return ret;
> +}
> +
> +static void zx_drm_unbind(struct device *dev)
> +{
> + struct drm_device *drm = dev_get_drvdata(dev);
> + struct zx_drm_private *priv = drm->dev_private;
> +
> + if (priv->fbdev) {
> + drm_fbdev_cma_fini(priv->fbdev);
> + priv->fbdev = NULL;
> + }
> + drm_kms_helper_poll_fini(drm);
> + component_unbind_all(dev, drm);
> + drm_vblank_cleanup(drm);
> + drm_mode_config_cleanup(drm);
> + drm_dev_unregister(drm);
> + drm_dev_unref(drm);
> + drm->dev_private = NULL;
> + dev_set_drvdata(dev, NULL);
> +}
> +
> +static const struct component_master_ops zx_drm_master_ops = {
> + .bind = zx_drm_bind,
> + .unbind = zx_drm_unbind,
> +};
> +
> +static int compare_of(struct device *dev, void *data)
> +{
> + return dev->of_node == data;
> +}
> +
> +static int zx_drm_probe(struct platform_device *pdev)
> +{
> + struct device *dev = &pdev->dev;
> + struct device_node *parent = dev->of_node;
> + struct device_node *child;
> + struct component_match *match = NULL;
> + int ret;
> +
> + ret = of_platform_populate(parent, NULL, NULL, dev);
> + if (ret)
> + return ret;
> +
> + for_each_available_child_of_node(parent, child) {
> + component_match_add(dev, &match, compare_of, child);
> + of_node_put(child);
> + }
> +
> + return component_master_add_with_match(dev, &zx_drm_master_ops, match);
> +}
> +
> +static int zx_drm_remove(struct platform_device *pdev)
> +{
> + component_master_del(&pdev->dev, &zx_drm_master_ops);
> + return 0;
> +}
> +
> +static const struct of_device_id zx_drm_of_match[] = {
> + { .compatible = "zte,zx296718-vou", },
> + { /* end */ },
> +};
> +MODULE_DEVICE_TABLE(of, zx_drm_of_match);
> +
> +static struct platform_driver zx_drm_platform_driver = {
> + .probe = zx_drm_probe,
> + .remove = zx_drm_remove,
> + .driver = {
> + .name = "zx-drm",
> + .of_match_table = zx_drm_of_match,
> + },
> +};
> +
> +static struct platform_driver *drivers[] = {
> + &zx_crtc_driver,
> + &zx_hdmi_driver,
> + &zx_drm_platform_driver,
> +};
> +
> +static int zx_drm_init(void)
> +{
> + return platform_register_drivers(drivers, ARRAY_SIZE(drivers));
> +}
> +module_init(zx_drm_init);
> +
> +static void zx_drm_exit(void)
> +{
> + platform_unregister_drivers(drivers, ARRAY_SIZE(drivers));
> +}
> +module_exit(zx_drm_exit);
> +
> +MODULE_AUTHOR("Shawn Guo <shawn.guo@linaro.org>");
> +MODULE_DESCRIPTION("ZTE ZX VOU DRM driver");
> +MODULE_LICENSE("GPL v2");
> diff --git a/drivers/gpu/drm/zte/zx_drm_drv.h b/drivers/gpu/drm/zte/zx_drm_drv.h
> new file mode 100644
> index 000000000000..14c749949151
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_drm_drv.h
> @@ -0,0 +1,22 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * 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 __ZX_DRM_DRV_H__
> +#define __ZX_DRM_DRV_H__
> +
> +struct zx_drm_private {
> + struct drm_fbdev_cma *fbdev;
> + struct zx_vou_hw *vou;
> +};
> +
> +extern struct platform_driver zx_crtc_driver;
> +extern struct platform_driver zx_hdmi_driver;
> +
> +#endif /* __ZX_DRM_DRV_H__ */
> diff --git a/drivers/gpu/drm/zte/zx_hdmi.c b/drivers/gpu/drm/zte/zx_hdmi.c
> new file mode 100644
> index 000000000000..5aaab8493b1b
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_hdmi.c
> @@ -0,0 +1,540 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * 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 <drm/drm_of.h>
> +#include <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_crtc_helper.h>
> +#include <drm/drm_edid.h>
> +#include <linux/irq.h>
> +#include <linux/clk.h>
> +#include <linux/delay.h>
> +#include <linux/err.h>
> +#include <linux/hdmi.h>
> +#include <linux/mfd/syscon.h>
> +#include <linux/module.h>
> +#include <linux/mutex.h>
> +#include <linux/of_device.h>
> +#include <linux/component.h>
> +
> +#include "zx_crtc.h"
> +
> +#define FUNC_SEL 0x000b
> +#define FUNC_HDMI_EN BIT(0)
> +#define CLKPWD 0x000d
> +#define CLKPWD_PDIDCK BIT(2)
> +#define PWD_SRST 0x0010
> +#define P2T_CTRL 0x0066
> +#define P2T_DC_PKT_EN BIT(7)
> +#define L1_INTR_STAT 0x007e
> +#define L1_INTR_STAT_INTR1 BIT(0)
> +#define INTR1_STAT 0x008f
> +#define INTR1_MASK 0x0095
> +#define INTR1_MONITOR_DETECT (BIT(5) | BIT(6))
> +#define ZX_DDC_ADDR 0x00ed
> +#define ZX_DDC_SEGM 0x00ee
> +#define ZX_DDC_OFFSET 0x00ef
> +#define ZX_DDC_DIN_CNT1 0x00f0
> +#define ZX_DDC_DIN_CNT2 0x00f1
> +#define ZX_DDC_CMD 0x00f3
> +#define DDC_CMD_MASK 0xf
> +#define DDC_CMD_CLEAR_FIFO 0x9
> +#define DDC_CMD_SEQUENTIAL_READ 0x2
> +#define ZX_DDC_DATA 0x00f4
> +#define ZX_DDC_DOUT_CNT 0x00f5
> +#define DDC_DOUT_CNT_MASK 0x1f
> +#define TEST_TXCTRL 0x00f7
> +#define TEST_TXCTRL_HDMI_MODE BIT(1)
> +#define HDMICTL4 0x0235
> +#define TPI_HPD_RSEN 0x063b
> +#define TPI_HPD_CONNECTION (BIT(1) | BIT(2))
> +#define TPI_INFO_FSEL 0x06bf
> +#define FSEL_AVI 0
> +#define FSEL_GBD 1
> +#define FSEL_AUDIO 2
> +#define FSEL_SPD 3
> +#define FSEL_MPEG 4
> +#define FSEL_VSIF 5
> +#define TPI_INFO_B0 0x06c0
> +#define TPI_INFO_EN 0x06df
> +#define TPI_INFO_TRANS_EN BIT(7)
> +#define TPI_INFO_TRANS_RPT BIT(6)
> +#define TPI_DDC_MASTER_EN 0x06f8
> +#define HW_DDC_MASTER BIT(7)
> +
> +#define ZX_HDMI_INFOFRAME_SIZE 31
> +
> +struct zx_hdmi {
> + struct drm_connector connector;
> + struct drm_encoder encoder;
> + struct device *dev;
> + struct drm_device *drm;
> + void __iomem *mmio;
> + struct clk *cec_clk;
> + struct clk *osc_clk;
> + struct clk *xclk;
> + bool sink_is_hdmi;
> + bool sink_has_audio;
> + struct vou_inf *inf;
> +};
> +
> +#define to_zx_hdmi(x) container_of(x, struct zx_hdmi, x)
> +
> +static struct vou_inf vou_inf_hdmi = {
> + .id = VOU_HDMI,
> + .data_sel = VOU_YUV444,
> + .clocks_en_bits = BIT(24) | BIT(18) | BIT(6),
> + .clocks_sel_bits = BIT(13) | BIT(2),
> +};
This should be static const, but I suppose you can't b/c you're
storing a pointer to encoder in vou_inf. This type of information
lends itself well to being defined and mapped as of_device_id.data,
you'll need to pass the encoder around in a different manner.
> +
> +static inline u8 hdmi_readb(struct zx_hdmi *hdmi, u16 offset)
> +{
> + return readl_relaxed(hdmi->mmio + offset * 4);
> +}
> +
> +static inline void hdmi_writeb(struct zx_hdmi *hdmi, u16 offset, u8 val)
> +{
> + writel_relaxed(val, hdmi->mmio + offset * 4);
> +}
> +
> +static int zx_hdmi_infoframe_trans(struct zx_hdmi *hdmi,
> + union hdmi_infoframe *frame, u8 fsel)
> +{
> + u8 buffer[ZX_HDMI_INFOFRAME_SIZE];
> + u8 val;
> + ssize_t num;
> + int i;
> +
> + hdmi_writeb(hdmi, TPI_INFO_FSEL, fsel);
> +
> + num = hdmi_infoframe_pack(frame, buffer, ZX_HDMI_INFOFRAME_SIZE);
> + if (num < 0)
> + return num;
> +
> + for (i = 0; i < num; i++)
> + hdmi_writeb(hdmi, TPI_INFO_B0 + i, buffer[i]);
> +
> + val = hdmi_readb(hdmi, TPI_INFO_EN);
> + val |= TPI_INFO_TRANS_EN | TPI_INFO_TRANS_RPT;
> + hdmi_writeb(hdmi, TPI_INFO_EN, val);
> +
> + return num;
> +}
> +
> +static int zx_hdmi_config_video_vsi(struct zx_hdmi *hdmi,
> + struct drm_display_mode *mode)
> +{
> + union hdmi_infoframe frame;
> + int ret;
> +
> + ret = drm_hdmi_vendor_infoframe_from_display_mode(&frame.vendor.hdmi,
> + mode);
> + if (ret)
Should you log in cases of failure (here and elsewhere)?
> + return ret;
> +
> + return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_VSIF);
> +}
> +
> +static int zx_hdmi_config_video_avi(struct zx_hdmi *hdmi,
> + struct drm_display_mode *mode)
> +{
> + union hdmi_infoframe frame;
> + int ret;
> +
> + ret = drm_hdmi_avi_infoframe_from_display_mode(&frame.avi, mode);
> + if (ret)
> + return ret;
> +
> + /* We always use YUV444 for HDMI output. */
> + frame.avi.colorspace = HDMI_COLORSPACE_YUV444;
> +
> + return zx_hdmi_infoframe_trans(hdmi, &frame, FSEL_AVI);
> +}
> +
> +static void zx_hdmi_encoder_mode_set(struct drm_encoder *encoder,
> + struct drm_display_mode *mode,
> + struct drm_display_mode *adj_mode)
> +{
> + struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
> +
> + if (hdmi->sink_is_hdmi) {
> + zx_hdmi_config_video_avi(hdmi, mode);
> + zx_hdmi_config_video_vsi(hdmi, mode);
> + }
> +}
> +
> +static void zx_hdmi_encoder_enable(struct drm_encoder *encoder)
> +{
> + struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
> +
> + vou_inf_enable(hdmi->inf);
I think you can remove the encoder from inf by passing encoder->crtc
here as well. That will tell vou which encoder/crtc pair to enable
without having that pesky static global floating around.
> +}
> +
> +static void zx_hdmi_encoder_disable(struct drm_encoder *encoder)
> +{
> + struct zx_hdmi *hdmi = to_zx_hdmi(encoder);
> +
> + vou_inf_disable(hdmi->inf);
Same here
> +}
> +
> +static const struct drm_encoder_helper_funcs zx_hdmi_encoder_helper_funcs = {
> + .enable = zx_hdmi_encoder_enable,
> + .disable = zx_hdmi_encoder_disable,
> + .mode_set = zx_hdmi_encoder_mode_set,
> +};
> +
> +static const struct drm_encoder_funcs zx_hdmi_encoder_funcs = {
> + .destroy = drm_encoder_cleanup,
> +};
> +
> +static int zx_hdmi_get_edid_block(void *data, u8 *buf, unsigned int block,
> + size_t len)
Instead of open-coding this, consider implementing an i2c adapter for
the DDC bus and use drm_get_edid below.
> +{
> + struct zx_hdmi *hdmi = data;
> + int retry = 0;
> + int ret = 0;
> + int i = 0;
> + u8 val;
> +
> + /* Enable DDC master access */
> + val = hdmi_readb(hdmi, TPI_DDC_MASTER_EN);
> + val |= HW_DDC_MASTER;
> + hdmi_writeb(hdmi, TPI_DDC_MASTER_EN, val);
> +
> + hdmi_writeb(hdmi, ZX_DDC_ADDR, 0xa0);
> + hdmi_writeb(hdmi, ZX_DDC_OFFSET, block * EDID_LENGTH);
> + /* Bits [9:8] of bytes */
> + hdmi_writeb(hdmi, ZX_DDC_DIN_CNT2, (len >> 8) & 0xff);
> + /* Bits [7:0] of bytes */
> + hdmi_writeb(hdmi, ZX_DDC_DIN_CNT1, len & 0xff);
> +
> + /* Clear FIFO */
> + val = hdmi_readb(hdmi, ZX_DDC_CMD);
> + val &= ~DDC_CMD_MASK;
> + val |= DDC_CMD_CLEAR_FIFO;
> + hdmi_writeb(hdmi, ZX_DDC_CMD, val);
> +
> + /* Kick off the read */
> + val = hdmi_readb(hdmi, ZX_DDC_CMD);
> + val &= ~DDC_CMD_MASK;
> + val |= DDC_CMD_SEQUENTIAL_READ;
> + hdmi_writeb(hdmi, ZX_DDC_CMD, val);
> +
> + while (len > 0) {
> + int cnt, j;
> +
> + /* FIFO needs some time to get ready */
> + usleep_range(500, 1000);
> +
> + cnt = hdmi_readb(hdmi, ZX_DDC_DOUT_CNT) & DDC_DOUT_CNT_MASK;
> + if (cnt == 0) {
> + if (++retry > 5) {
> + dev_err(hdmi->dev, "DDC read timed out!");
> + ret = -ETIMEDOUT;
> + break;
> + }
> + continue;
> + }
> +
> + for (j = 0; j < cnt; j++)
> + buf[i++] = hdmi_readb(hdmi, ZX_DDC_DATA);
> + len -= cnt;
> + }
> +
> + /* Disable DDC master access */
> + val = hdmi_readb(hdmi, TPI_DDC_MASTER_EN);
> + val &= ~HW_DDC_MASTER;
> + hdmi_writeb(hdmi, TPI_DDC_MASTER_EN, val);
> +
> + return ret;
> +}
> +
> +static int zx_hdmi_connector_get_modes(struct drm_connector *connector)
> +{
> + struct zx_hdmi *hdmi = to_zx_hdmi(connector);
> + struct edid *edid;
> + int ret = 0;
> +
> + edid = drm_do_get_edid(connector, zx_hdmi_get_edid_block, hdmi);
> + if (edid) {
> + hdmi->sink_is_hdmi = drm_detect_hdmi_monitor(edid);
> + hdmi->sink_has_audio = drm_detect_monitor_audio(edid);
> + drm_mode_connector_update_edid_property(connector, edid);
> + ret = drm_add_edid_modes(connector, edid);
> + kfree(edid);
> + }
> +
> + return ret;
> +}
> +
> +static enum drm_mode_status
> +zx_hdmi_connector_mode_valid(struct drm_connector *connector,
> + struct drm_display_mode *mode)
> +{
> + return MODE_OK;
> +}
> +
> +static struct drm_connector_helper_funcs zx_hdmi_connector_helper_funcs = {
> + .get_modes = zx_hdmi_connector_get_modes,
> + .mode_valid = zx_hdmi_connector_mode_valid,
> +};
> +
> +static enum drm_connector_status
> +zx_hdmi_connector_detect(struct drm_connector *connector, bool force)
> +{
> + struct zx_hdmi *hdmi = to_zx_hdmi(connector);
> +
> + return (hdmi_readb(hdmi, TPI_HPD_RSEN) & TPI_HPD_CONNECTION) ?
> + connector_status_connected : connector_status_disconnected;
> +}
> +
> +static void zx_hdmi_connector_destroy(struct drm_connector *connector)
> +{
> + drm_connector_unregister(connector);
> + drm_connector_cleanup(connector);
> +}
> +
> +static const struct drm_connector_funcs zx_hdmi_connector_funcs = {
> + .dpms = drm_atomic_helper_connector_dpms,
> + .fill_modes = drm_helper_probe_single_connector_modes,
> + .detect = zx_hdmi_connector_detect,
> + .destroy = zx_hdmi_connector_destroy,
> + .reset = drm_atomic_helper_connector_reset,
> + .atomic_duplicate_state = drm_atomic_helper_connector_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_connector_destroy_state,
> +};
> +
> +static int zx_hdmi_register(struct drm_device *drm, struct zx_hdmi *hdmi)
> +{
> + struct drm_encoder *encoder = &hdmi->encoder;
> +
> + encoder->possible_crtcs = VOU_CRTC_MASK;
> +
> + drm_encoder_init(drm, encoder, &zx_hdmi_encoder_funcs,
> + DRM_MODE_ENCODER_TMDS, NULL);
> + drm_encoder_helper_add(encoder, &zx_hdmi_encoder_helper_funcs);
> +
> + hdmi->connector.polled = DRM_CONNECTOR_POLL_HPD;
> +
> + drm_connector_init(drm, &hdmi->connector, &zx_hdmi_connector_funcs,
> + DRM_MODE_CONNECTOR_HDMIA);
> + drm_connector_helper_add(&hdmi->connector,
> + &zx_hdmi_connector_helper_funcs);
> +
> + drm_mode_connector_attach_encoder(&hdmi->connector, encoder);
> + drm_connector_register(&hdmi->connector);
> +
> + return 0;
> +}
> +
> +static irqreturn_t zx_hdmi_irq_thread(int irq, void *dev_id)
> +{
> + struct zx_hdmi *hdmi = dev_id;
> +
> + drm_helper_hpd_irq_event(hdmi->connector.dev);
> +
> + return IRQ_HANDLED;
> +}
> +
> +static irqreturn_t zx_hdmi_irq_handler(int irq, void *dev_id)
> +{
> + struct zx_hdmi *hdmi = dev_id;
> + u8 lstat;
> +
> + lstat = hdmi_readb(hdmi, L1_INTR_STAT);
> +
> + /* Monitor detect/HPD interrupt */
> + if (lstat & L1_INTR_STAT_INTR1) {
> + u8 stat = hdmi_readb(hdmi, INTR1_STAT);
> +
> + hdmi_writeb(hdmi, INTR1_STAT, stat);
> + if (stat & INTR1_MONITOR_DETECT)
> + return IRQ_WAKE_THREAD;
> + }
> +
> + return IRQ_NONE;
> +}
> +
> +static void zx_hdmi_phy_start(struct zx_hdmi *hdmi)
> +{
> + /* Copy from ZTE BSP code */
> + hdmi_writeb(hdmi, 0x222, 0x0);
> + hdmi_writeb(hdmi, 0x224, 0x4);
> + hdmi_writeb(hdmi, 0x909, 0x0);
> + hdmi_writeb(hdmi, 0x7b0, 0x90);
> + hdmi_writeb(hdmi, 0x7b1, 0x00);
> + hdmi_writeb(hdmi, 0x7b2, 0xa7);
> + hdmi_writeb(hdmi, 0x7b8, 0xaa);
> + hdmi_writeb(hdmi, 0x7b2, 0xa7);
> + hdmi_writeb(hdmi, 0x7b3, 0x0f);
> + hdmi_writeb(hdmi, 0x7b4, 0x0f);
> + hdmi_writeb(hdmi, 0x7b5, 0x55);
> + hdmi_writeb(hdmi, 0x7b7, 0x03);
> + hdmi_writeb(hdmi, 0x7b9, 0x12);
> + hdmi_writeb(hdmi, 0x7ba, 0x32);
> + hdmi_writeb(hdmi, 0x7bc, 0x68);
> + hdmi_writeb(hdmi, 0x7be, 0x40);
> + hdmi_writeb(hdmi, 0x7bf, 0x84);
> + hdmi_writeb(hdmi, 0x7c1, 0x0f);
> + hdmi_writeb(hdmi, 0x7c8, 0x02);
> + hdmi_writeb(hdmi, 0x7c9, 0x03);
> + hdmi_writeb(hdmi, 0x7ca, 0x40);
> + hdmi_writeb(hdmi, 0x7dc, 0x31);
> + hdmi_writeb(hdmi, 0x7e2, 0x04);
> + hdmi_writeb(hdmi, 0x7e0, 0x06);
> + hdmi_writeb(hdmi, 0x7cb, 0x68);
> + hdmi_writeb(hdmi, 0x7f9, 0x02);
> + hdmi_writeb(hdmi, 0x7b6, 0x02);
> + hdmi_writeb(hdmi, 0x7f3, 0x0);
> +}
> +
> +static void zx_hdmi_hw_init(struct zx_hdmi *hdmi)
> +{
> + u8 val;
> +
> + /* Software reset */
> + hdmi_writeb(hdmi, PWD_SRST, 1);
> +
> + /* Enable pclk */
> + val = hdmi_readb(hdmi, CLKPWD);
> + val |= CLKPWD_PDIDCK;
> + hdmi_writeb(hdmi, CLKPWD, val);
> +
> + /* Enable HDMI for TX */
> + val = hdmi_readb(hdmi, FUNC_SEL);
> + val |= FUNC_HDMI_EN;
> + hdmi_writeb(hdmi, FUNC_SEL, val);
> +
> + /* Enable deep color packet */
> + val = hdmi_readb(hdmi, P2T_CTRL);
> + val |= P2T_DC_PKT_EN;
> + hdmi_writeb(hdmi, P2T_CTRL, val);
> +
> + /* Enable HDMI/MHL mode for output */
> + val = hdmi_readb(hdmi, TEST_TXCTRL);
> + val |= TEST_TXCTRL_HDMI_MODE;
> + hdmi_writeb(hdmi, TEST_TXCTRL, val);
> +
> + /* Configure reg_qc_sel */
> + hdmi_writeb(hdmi, HDMICTL4, 0x3);
> +
> + /* Enable interrupt */
> + val = hdmi_readb(hdmi, INTR1_MASK);
> + val |= INTR1_MONITOR_DETECT;
> + hdmi_writeb(hdmi, INTR1_MASK, val);
> +
> + /* Clear reset for normal operation */
> + hdmi_writeb(hdmi, PWD_SRST, 0);
> +
> + /* Start up phy */
> + zx_hdmi_phy_start(hdmi);
> +}
> +
> +static int zx_hdmi_bind(struct device *dev, struct device *master, void *data)
> +{
> + struct platform_device *pdev = to_platform_device(dev);
> + struct drm_device *drm = data;
> + struct resource *res;
> + struct zx_hdmi *hdmi;
> + struct vou_inf *inf;
> + int irq;
> + int ret;
> +
> + hdmi = devm_kzalloc(dev, sizeof(*hdmi), GFP_KERNEL);
> + if (!hdmi)
> + return -ENOMEM;
> +
> + hdmi->dev = dev;
> + hdmi->drm = drm;
> +
> + inf = &vou_inf_hdmi;
> + inf->encoder = &hdmi->encoder;
> + hdmi->inf = inf;
> +
> + dev_set_drvdata(dev, hdmi);
> +
> + res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
> + hdmi->mmio = devm_ioremap_resource(dev, res);
> + if (IS_ERR(hdmi->mmio))
> + return PTR_ERR(hdmi->mmio);
> +
> + irq = platform_get_irq(pdev, 0);
> + if (irq < 0)
> + return irq;
> +
> + hdmi->cec_clk = devm_clk_get(hdmi->dev, "osc_cec");
> + if (IS_ERR(hdmi->cec_clk))
> + return PTR_ERR(hdmi->cec_clk);
> +
> + hdmi->osc_clk = devm_clk_get(hdmi->dev, "osc_clk");
> + if (IS_ERR(hdmi->osc_clk))
> + return PTR_ERR(hdmi->osc_clk);
> +
> + hdmi->xclk = devm_clk_get(hdmi->dev, "xclk");
> + if (IS_ERR(hdmi->xclk))
> + return PTR_ERR(hdmi->xclk);
> +
> + zx_hdmi_hw_init(hdmi);
> +
> + clk_prepare_enable(hdmi->cec_clk);
> + clk_prepare_enable(hdmi->osc_clk);
> + clk_prepare_enable(hdmi->xclk);
> +
> + ret = zx_hdmi_register(drm, hdmi);
> + if (ret)
> + return ret;
> +
> + ret = devm_request_threaded_irq(dev, irq, zx_hdmi_irq_handler,
> + zx_hdmi_irq_thread, IRQF_SHARED,
> + dev_name(dev), hdmi);
> +
> + return 0;
> +}
> +
> +static void zx_hdmi_unbind(struct device *dev, struct device *master,
> + void *data)
> +{
> + struct zx_hdmi *hdmi = dev_get_drvdata(dev);
> +
> + clk_disable_unprepare(hdmi->cec_clk);
> + clk_disable_unprepare(hdmi->osc_clk);
> + clk_disable_unprepare(hdmi->xclk);
> +}
> +
> +static const struct component_ops zx_hdmi_component_ops = {
> + .bind = zx_hdmi_bind,
> + .unbind = zx_hdmi_unbind,
> +};
> +
> +static int zx_hdmi_probe(struct platform_device *pdev)
> +{
> + return component_add(&pdev->dev, &zx_hdmi_component_ops);
> +}
> +
> +static int zx_hdmi_remove(struct platform_device *pdev)
> +{
> + component_del(&pdev->dev, &zx_hdmi_component_ops);
> + return 0;
> +}
> +
> +static const struct of_device_id zx_hdmi_of_match[] = {
> + { .compatible = "zte,zx296718-hdmi", },
> + { /* end */ },
> +};
> +MODULE_DEVICE_TABLE(of, zx_hdmi_of_match);
> +
> +struct platform_driver zx_hdmi_driver = {
> + .probe = zx_hdmi_probe,
> + .remove = zx_hdmi_remove,
> + .driver = {
> + .name = "zx-hdmi",
> + .of_match_table = zx_hdmi_of_match,
> + },
> +};
> diff --git a/drivers/gpu/drm/zte/zx_plane.c b/drivers/gpu/drm/zte/zx_plane.c
> new file mode 100644
> index 000000000000..326cc1ff7950
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_plane.c
> @@ -0,0 +1,362 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * 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 <drm/drmP.h>
> +#include <drm/drm_atomic_helper.h>
> +#include <drm/drm_fb_cma_helper.h>
> +#include <drm/drm_gem_cma_helper.h>
> +#include <drm/drm_modeset_helper_vtables.h>
> +#include <drm/drm_plane_helper.h>
> +
> +#include "zx_crtc.h"
> +#include "zx_plane.h"
> +
> +/* GL registers */
> +#define GL_CTRL0 0x00
> +#define GL_UPDATE BIT(5)
> +#define GL_CTRL1 0x04
> +#define GL_DATA_FMT_SHIFT 0
> +#define GL_DATA_FMT_MASK (0xf << GL_DATA_FMT_SHIFT)
> +#define GL_FMT_ARGB8888 0
> +#define GL_FMT_RGB888 1
> +#define GL_FMT_RGB565 2
> +#define GL_FMT_ARGB1555 3
> +#define GL_FMT_ARGB4444 4
> +#define GL_CTRL2 0x08
> +#define GL_GLOBAL_ALPHA_SHIFT 8
> +#define GL_GLOBAL_ALPHA_MASK (0xff << GL_GLOBAL_ALPHA_SHIFT)
> +#define GL_CTRL3 0x0c
> +#define GL_SCALER_BYPASS_MODE BIT(0)
> +#define GL_STRIDE 0x18
> +#define GL_ADDR 0x1c
> +#define GL_SRC_SIZE 0x38
> +#define GL_SRC_W_SHIFT 16
> +#define GL_SRC_W_MASK (0x3fff << GL_SRC_W_SHIFT)
> +#define GL_SRC_H_SHIFT 0
> +#define GL_SRC_H_MASK (0x3fff << GL_SRC_H_SHIFT)
> +#define GL_POS_START 0x9c
> +#define GL_POS_END 0xa0
> +#define GL_POS_X_SHIFT 16
> +#define GL_POS_X_MASK (0x1fff << GL_POS_X_SHIFT)
> +#define GL_POS_Y_SHIFT 0
> +#define GL_POS_Y_MASK (0x1fff << GL_POS_Y_SHIFT)
> +
> +/* CSC registers */
> +#define CSC_CTRL0 0x30
> +#define CSC_COV_MODE_SHIFT 16
> +#define CSC_COV_MODE_MASK (0xffff << CSC_COV_MODE_SHIFT)
> +#define CSC_BT601_IMAGE_RGB2YCBCR 0
> +#define CSC_BT601_IMAGE_YCBCR2RGB 1
> +#define CSC_BT601_VIDEO_RGB2YCBCR 2
> +#define CSC_BT601_VIDEO_YCBCR2RGB 3
> +#define CSC_BT709_IMAGE_RGB2YCBCR 4
> +#define CSC_BT709_IMAGE_YCBCR2RGB 5
> +#define CSC_BT709_VIDEO_RGB2YCBCR 6
> +#define CSC_BT709_VIDEO_YCBCR2RGB 7
> +#define CSC_BT2020_IMAGE_RGB2YCBCR 8
> +#define CSC_BT2020_IMAGE_YCBCR2RGB 9
> +#define CSC_BT2020_VIDEO_RGB2YCBCR 10
> +#define CSC_BT2020_VIDEO_YCBCR2RGB 11
> +#define CSC_WORK_ENABLE BIT(0)
> +
> +/* RSZ registers */
> +#define RSZ_SRC_CFG 0x00
> +#define RSZ_DEST_CFG 0x04
> +#define RSZ_ENABLE_CFG 0x14
> +
> +/* HBSC registers */
> +#define HBSC_SATURATION 0x00
> +#define HBSC_HUE 0x04
> +#define HBSC_BRIGHT 0x08
> +#define HBSC_CONTRAST 0x0c
> +#define HBSC_THRESHOLD_COL1 0x10
> +#define HBSC_THRESHOLD_COL2 0x14
> +#define HBSC_THRESHOLD_COL3 0x18
> +#define HBSC_CTRL0 0x28
> +#define HBSC_CTRL_EN BIT(2)
> +
> +struct zx_plane {
> + struct drm_plane plane;
> + void __iomem *layer;
> + void __iomem *csc;
> + void __iomem *hbsc;
> + void __iomem *rsz;
> +};
> +
> +#define to_zx_plane(plane) container_of(plane, struct zx_plane, plane)
> +
> +static const uint32_t gl_formats[] = {
> + DRM_FORMAT_ARGB8888,
> + DRM_FORMAT_XRGB8888,
> + DRM_FORMAT_RGB888,
> + DRM_FORMAT_RGB565,
> + DRM_FORMAT_ARGB1555,
> + DRM_FORMAT_ARGB4444,
> +};
> +
> +static int zx_gl_plane_atomic_check(struct drm_plane *plane,
> + struct drm_plane_state *state)
> +{
> + u32 src_w, src_h;
> +
> + src_w = state->src_w >> 16;
> + src_h = state->src_h >> 16;
> +
> + /* TODO: support scaling of the plane source */
> + if ((src_w != state->crtc_w) || (src_h != state->crtc_h))
> + return -EINVAL;
> +
> + return 0;
> +}
> +
> +static int zx_gl_get_fmt(uint32_t format)
> +{
> + switch (format) {
> + case DRM_FORMAT_ARGB8888:
> + case DRM_FORMAT_XRGB8888:
> + return GL_FMT_ARGB8888;
> + case DRM_FORMAT_RGB888:
> + return GL_FMT_RGB888;
> + case DRM_FORMAT_RGB565:
> + return GL_FMT_RGB565;
> + case DRM_FORMAT_ARGB1555:
> + return GL_FMT_ARGB1555;
> + case DRM_FORMAT_ARGB4444:
> + return GL_FMT_ARGB4444;
> + default:
> + WARN_ONCE(1, "invalid pixel format %d\n", format);
> + return -EINVAL;
> + }
> +}
> +
> +static inline void zx_gl_set_update(struct zx_plane *zplane)
> +{
> + void __iomem *layer = zplane->layer;
> + u32 val;
> +
> + val = readl(layer + GL_CTRL0);
> + val |= GL_UPDATE;
> + writel(val, layer + GL_CTRL0);
> +}
> +
> +static inline void zx_gl_rsz_set_update(struct zx_plane *zplane)
> +{
> + writel(1, zplane->rsz + RSZ_ENABLE_CFG);
> +}
> +
> +void zx_plane_set_update(struct drm_plane *plane)
> +{
> + struct zx_plane *zplane = to_zx_plane(plane);
> +
> + zx_gl_rsz_set_update(zplane);
> + zx_gl_set_update(zplane);
> +}
> +
> +static void zx_gl_rsz_setup(struct zx_plane *zplane, u32 src_w, u32 src_h,
> + u32 dst_w, u32 dst_h)
> +{
> + void __iomem *rsz = zplane->rsz;
> + u32 val;
> +
> + val = ((src_h - 1) & 0xffff) << 16;
> + val |= (src_w - 1) & 0xffff;
> + writel(val, rsz + RSZ_SRC_CFG);
> +
> + val = ((dst_h - 1) & 0xffff) << 16;
> + val |= (dst_w - 1) & 0xffff;
> + writel(val, rsz + RSZ_DEST_CFG);
> +
> + zx_gl_rsz_set_update(zplane);
> +}
> +
> +static void zx_gl_plane_atomic_update(struct drm_plane *plane,
> + struct drm_plane_state *old_state)
> +{
> + struct zx_plane *zplane = to_zx_plane(plane);
> + struct drm_framebuffer *fb = plane->state->fb;
> + struct drm_gem_cma_object *cma_obj;
> + void __iomem *layer = zplane->layer;
> + void __iomem *csc = zplane->csc;
> + void __iomem *hbsc = zplane->hbsc;
> + u32 src_x, src_y, src_w, src_h;
> + u32 dst_x, dst_y, dst_w, dst_h;
> + unsigned int depth, bpp;
> + uint32_t format;
> + dma_addr_t paddr;
> + u32 stride;
> + int fmt;
> + u32 val;
> +
> + if (!fb)
> + return;
> +
> + format = fb->pixel_format;
> + stride = fb->pitches[0];
> +
> + src_x = plane->state->src_x >> 16;
> + src_y = plane->state->src_y >> 16;
> + src_w = plane->state->src_w >> 16;
> + src_h = plane->state->src_h >> 16;
> +
> + dst_x = plane->state->crtc_x;
> + dst_y = plane->state->crtc_y;
> + dst_w = plane->state->crtc_w;
> + dst_h = plane->state->crtc_h;
> +
> + drm_fb_get_bpp_depth(format, &depth, &bpp);
> +
> + cma_obj = drm_fb_cma_get_gem_obj(fb, 0);
> + paddr = cma_obj->paddr + fb->offsets[0];
> + paddr += src_y * stride + src_x * bpp / 8;
> + writel(paddr, layer + GL_ADDR);
> +
> + /* Set up source height/width register */
> + val = (src_w << GL_SRC_W_SHIFT) & GL_SRC_W_MASK;
> + val |= (src_h << GL_SRC_H_SHIFT) & GL_SRC_H_MASK;
> + writel(val, layer + GL_SRC_SIZE);
> +
> + /* Set up start position register */
> + val = (dst_x << GL_POS_X_SHIFT) & GL_POS_X_MASK;
> + val |= (dst_y << GL_POS_Y_SHIFT) & GL_POS_Y_MASK;
> + writel(val, layer + GL_POS_START);
> +
> + /* Set up end position register */
> + val = ((dst_x + dst_w) << GL_POS_X_SHIFT) & GL_POS_X_MASK;
> + val |= ((dst_y + dst_h) << GL_POS_Y_SHIFT) & GL_POS_Y_MASK;
> + writel(val, layer + GL_POS_END);
> +
> + /* Set up stride register */
> + writel(stride & 0xffff, layer + GL_STRIDE);
> +
> + /* Set up graphic layer data format */
> + fmt = zx_gl_get_fmt(format);
> + if (fmt >= 0) {
> + val = readl(layer + GL_CTRL1);
> + val &= ~GL_DATA_FMT_MASK;
> + val |= fmt << GL_DATA_FMT_SHIFT;
> + writel(val, layer + GL_CTRL1);
> + }
> +
> + /* Initialize global alpha with a sane value */
> + val = readl(layer + GL_CTRL2);
> + val &= ~GL_GLOBAL_ALPHA_MASK;
> + val |= 0xff << GL_GLOBAL_ALPHA_SHIFT;
> + writel(val, layer + GL_CTRL2);
> +
> + /* Setup CSC for the GL */
> + val = readl(csc + CSC_CTRL0);
> + val &= ~CSC_COV_MODE_MASK;
> + if (dst_h > 720)
> + val |= CSC_BT709_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT;
> + else
> + val |= CSC_BT601_IMAGE_RGB2YCBCR << CSC_COV_MODE_SHIFT;
> + val |= CSC_WORK_ENABLE;
> + writel(val, csc + CSC_CTRL0);
> +
> + /* Always use scaler since it exists */
> + val = readl(layer + GL_CTRL3);
> + val |= GL_SCALER_BYPASS_MODE; /* set for not bypass */
> + writel(val, layer + GL_CTRL3);
> +
> + zx_gl_rsz_setup(zplane, src_w, src_h, dst_w, dst_h);
> +
> + /* Enable HBSC block */
> + val = readl(hbsc + HBSC_CTRL0);
> + val |= HBSC_CTRL_EN;
> + writel(val, hbsc + HBSC_CTRL0);
> +
> + zx_gl_set_update(zplane);
> +}
> +
> +static const struct drm_plane_helper_funcs zx_gl_plane_helper_funcs = {
> + .atomic_check = zx_gl_plane_atomic_check,
> + .atomic_update = zx_gl_plane_atomic_update,
> +};
> +
> +static void zx_plane_destroy(struct drm_plane *plane)
> +{
> + drm_plane_helper_disable(plane);
> + drm_plane_cleanup(plane);
> +}
> +
> +static const struct drm_plane_funcs zx_plane_funcs = {
> + .update_plane = drm_atomic_helper_update_plane,
> + .disable_plane = drm_atomic_helper_disable_plane,
> + .destroy = zx_plane_destroy,
> + .reset = drm_atomic_helper_plane_reset,
> + .atomic_duplicate_state = drm_atomic_helper_plane_duplicate_state,
> + .atomic_destroy_state = drm_atomic_helper_plane_destroy_state,
> +};
> +
> +static void zx_plane_hbsc_init(struct zx_plane *zplane)
> +{
> + void __iomem *hbsc = zplane->hbsc;
> +
> + /*
> + * Initialize HBSC block with a sane configuration per recommedation
> + * from ZTE BSP code.
> + */
> + writel(0x200, hbsc + HBSC_SATURATION);
> + writel(0x0, hbsc + HBSC_HUE);
> + writel(0x0, hbsc + HBSC_BRIGHT);
> + writel(0x200, hbsc + HBSC_CONTRAST);
> +
> + writel((0x3ac << 16) | 0x40, hbsc + HBSC_THRESHOLD_COL1);
> + writel((0x3c0 << 16) | 0x40, hbsc + HBSC_THRESHOLD_COL2);
> + writel((0x3c0 << 16) | 0x40, hbsc + HBSC_THRESHOLD_COL3);
> +}
> +
> +struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
> + struct zx_layer_data *data,
> + enum drm_plane_type type)
> +{
> + const struct drm_plane_helper_funcs *helper;
> + struct zx_plane *zplane;
> + struct drm_plane *plane;
> + const uint32_t *formats;
> + unsigned int format_count;
> + int ret;
> +
> + zplane = devm_kzalloc(dev, sizeof(*zplane), GFP_KERNEL);
> + if (!zplane)
> + return ERR_PTR(-ENOMEM);
> +
> + plane = &zplane->plane;
> +
> + zplane->layer = data->layer;
> + zplane->hbsc = data->hbsc;
> + zplane->csc = data->csc;
> + zplane->rsz = data->rsz;
> +
> + zx_plane_hbsc_init(zplane);
> +
> + switch (type) {
> + case DRM_PLANE_TYPE_PRIMARY:
> + helper = &zx_gl_plane_helper_funcs;
> + formats = gl_formats;
> + format_count = ARRAY_SIZE(gl_formats);
> + break;
> + case DRM_PLANE_TYPE_OVERLAY:
> + /* TODO: add video layer (vl) support */
> + break;
> + default:
> + return ERR_PTR(-ENODEV);
> + }
> +
> + ret = drm_universal_plane_init(drm, plane, VOU_CRTC_MASK,
> + &zx_plane_funcs, formats, format_count,
> + type, NULL);
> + if (ret)
> + return ERR_PTR(ret);
> +
> + drm_plane_helper_add(plane, helper);
> +
> + return plane;
> +}
> diff --git a/drivers/gpu/drm/zte/zx_plane.h b/drivers/gpu/drm/zte/zx_plane.h
> new file mode 100644
> index 000000000000..2b82cd558d9d
> --- /dev/null
> +++ b/drivers/gpu/drm/zte/zx_plane.h
> @@ -0,0 +1,26 @@
> +/*
> + * Copyright 2016 Linaro Ltd.
> + * Copyright 2016 ZTE Corporation.
> + *
> + * 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 __ZX_PLANE_H__
> +#define __ZX_PLANE_H__
> +
> +struct zx_layer_data {
> + void __iomem *layer;
> + void __iomem *csc;
> + void __iomem *hbsc;
> + void __iomem *rsz;
> +};
> +
> +struct drm_plane *zx_plane_init(struct drm_device *drm, struct device *dev,
> + struct zx_layer_data *data,
> + enum drm_plane_type type);
> +void zx_plane_set_update(struct drm_plane *plane);
> +
> +#endif /* __ZX_PLANE_H__ */
> --
> 1.9.1
>
> _______________________________________________
> dri-devel mailing list
> dri-devel at lists.freedesktop.org
> https://lists.freedesktop.org/mailman/listinfo/dri-devel
^ 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