Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

mfd: dbx500: Provide a more accurate smp_twd clock

The local timer clock is based on ARM subsystem clock. This patch
obtains a more exact value of that clock by reading PRCMU registers.
Using this increases the accuracy of the local timer events.

Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
Signed-off-by: Rickard Andersson <rickard.andersson@stericsson.com>
Signed-off-by: Michel Jaouen <michel.jaouen@stericsson.com>
Acked-by: Linus Walleij <linus.walleij@linaro.org>
Signed-off-by: Samuel Ortiz <sameo@linux.intel.com>

authored by

Michel Jaouen and committed by
Samuel Ortiz
804971ec 0dd96360

+45 -1
+41
drivers/mfd/db8500-prcmu.c
··· 418 418 419 419 static atomic_t ac_wake_req_state = ATOMIC_INIT(0); 420 420 421 + /* Functions definition */ 422 + static void compute_armss_rate(void); 423 + 421 424 /* Spinlocks */ 422 425 static DEFINE_SPINLOCK(prcmu_lock); 423 426 static DEFINE_SPINLOCK(clkout_lock); ··· 1016 1013 (mb1_transfer.ack.arm_opp != opp)) 1017 1014 r = -EIO; 1018 1015 1016 + compute_armss_rate(); 1019 1017 mutex_unlock(&mb1_transfer.lock); 1020 1018 1021 1019 return r; ··· 1616 1612 if ((branch == PLL_FIX) || ((branch == PLL_DIV) && 1617 1613 (val & PRCM_PLL_FREQ_DIV2EN) && 1618 1614 ((reg == PRCM_PLLSOC0_FREQ) || 1615 + (reg == PRCM_PLLARM_FREQ) || 1619 1616 (reg == PRCM_PLLDDR_FREQ)))) 1620 1617 div *= 2; 1621 1618 ··· 1666 1661 else 1667 1662 return 0; 1668 1663 } 1664 + static unsigned long latest_armss_rate; 1665 + static unsigned long armss_rate(void) 1666 + { 1667 + return latest_armss_rate; 1668 + } 1669 + 1670 + static void compute_armss_rate(void) 1671 + { 1672 + u32 r; 1673 + unsigned long rate; 1674 + 1675 + r = readl(PRCM_ARM_CHGCLKREQ); 1676 + 1677 + if (r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ) { 1678 + /* External ARMCLKFIX clock */ 1679 + 1680 + rate = pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_FIX); 1681 + 1682 + /* Check PRCM_ARM_CHGCLKREQ divider */ 1683 + if (!(r & PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL)) 1684 + rate /= 2; 1685 + 1686 + /* Check PRCM_ARMCLKFIX_MGT divider */ 1687 + r = readl(PRCM_ARMCLKFIX_MGT); 1688 + r &= PRCM_CLK_MGT_CLKPLLDIV_MASK; 1689 + rate /= r; 1690 + 1691 + } else {/* ARM PLL */ 1692 + rate = pll_rate(PRCM_PLLARM_FREQ, ROOT_CLOCK_RATE, PLL_DIV); 1693 + } 1694 + 1695 + latest_armss_rate = rate; 1696 + } 1669 1697 1670 1698 static unsigned long dsiclk_rate(u8 n) 1671 1699 { ··· 1745 1707 return pll_rate(PRCM_PLLSOC0_FREQ, ROOT_CLOCK_RATE, PLL_RAW); 1746 1708 else if (clock == PRCMU_PLLSOC1) 1747 1709 return pll_rate(PRCM_PLLSOC1_FREQ, ROOT_CLOCK_RATE, PLL_RAW); 1710 + else if (clock == PRCMU_ARMSS) 1711 + return armss_rate(); 1748 1712 else if (clock == PRCMU_PLLDDR) 1749 1713 return pll_rate(PRCM_PLLDDR_FREQ, ROOT_CLOCK_RATE, PLL_RAW); 1750 1714 else if (clock == PRCMU_PLLDSI) ··· 2733 2693 handle_simple_irq); 2734 2694 set_irq_flags(irq, IRQF_VALID); 2735 2695 } 2696 + compute_armss_rate(); 2736 2697 } 2737 2698 2738 2699 static void __init init_prcm_registers(void)
+3 -1
drivers/mfd/dbx500-prcmu-regs.h
··· 61 61 #define PRCM_PLLARM_LOCKP_PRCM_PLLARM_LOCKP3 0x2 62 62 63 63 #define PRCM_ARM_CHGCLKREQ (_PRCMU_BASE + 0x114) 64 - #define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ 0x1 64 + #define PRCM_ARM_CHGCLKREQ_PRCM_ARM_CHGCLKREQ BIT(0) 65 + #define PRCM_ARM_CHGCLKREQ_PRCM_ARM_DIVSEL BIT(16) 65 66 66 67 #define PRCM_PLLARM_ENABLE (_PRCMU_BASE + 0x98) 67 68 #define PRCM_PLLARM_ENABLE_PRCM_PLLARM_ENABLE 0x1 ··· 141 140 /* PRCMU clock/PLL/reset registers */ 142 141 #define PRCM_PLLSOC0_FREQ (_PRCMU_BASE + 0x080) 143 142 #define PRCM_PLLSOC1_FREQ (_PRCMU_BASE + 0x084) 143 + #define PRCM_PLLARM_FREQ (_PRCMU_BASE + 0x088) 144 144 #define PRCM_PLLDDR_FREQ (_PRCMU_BASE + 0x08C) 145 145 #define PRCM_PLL_FREQ_D_SHIFT 0 146 146 #define PRCM_PLL_FREQ_D_MASK BITS(0, 7)
+1
include/linux/mfd/dbx500-prcmu.h
··· 136 136 PRCMU_TIMCLK, 137 137 PRCMU_PLLSOC0, 138 138 PRCMU_PLLSOC1, 139 + PRCMU_ARMSS, 139 140 PRCMU_PLLDDR, 140 141 PRCMU_PLLDSI, 141 142 PRCMU_DSI0CLK,