aboutsummaryrefslogtreecommitdiff
path: root/hw/misc
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2018-06-26 18:23:49 +0100
committerPeter Maydell <peter.maydell@linaro.org>2018-06-26 18:23:49 +0100
commit00928a421d47f49691cace1207481b7aad31b1f1 (patch)
treee28ed5e184928ae385737fbc03ddd9a59edef0f0 /hw/misc
parent7e2d08863b5cd4d35e6e0dc211b0cceaa350ade2 (diff)
parent9b945a9ee36a34eaeca412ef9ef35fbfe33c2c85 (diff)
downloadqemu-00928a421d47f49691cace1207481b7aad31b1f1.zip
qemu-00928a421d47f49691cace1207481b7aad31b1f1.tar.gz
qemu-00928a421d47f49691cace1207481b7aad31b1f1.tar.bz2
Merge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20180626' into staging
target-arm queue: * aspeed: set APB clocks correctly (fixes slowdown on palmetto) * smmuv3: cache config data and TLB entries * v7m/v8m: support read/write from MPU regions smaller than 1K * various: clean up logging/debug messages * xilinx_spips: Make dma transactions as per dma_burst_size # gpg: Signature made Tue 26 Jun 2018 17:55:46 BST # gpg: using RSA key 3C2525ED14360CDE # gpg: Good signature from "Peter Maydell <peter.maydell@linaro.org>" # gpg: aka "Peter Maydell <pmaydell@gmail.com>" # gpg: aka "Peter Maydell <pmaydell@chiark.greenend.org.uk>" # Primary key fingerprint: E1A5 C593 CD41 9DE2 8E83 15CF 3C25 25ED 1436 0CDE * remotes/pmaydell/tags/pull-target-arm-20180626: (32 commits) aspeed/timer: use the APB frequency from the SCU aspeed: initialize the SCU controller first aspeed/scu: introduce clock frequencies hw/arm/smmuv3: Add notifications on invalidation hw/arm/smmuv3: IOTLB emulation hw/arm/smmuv3: Cache/invalidate config data hw/arm/smmuv3: Fix translate error handling target/arm: Handle small regions in get_phys_addr_pmsav8() target/arm: Set page (region) size in get_phys_addr_pmsav7() tcg: Support MMU protection regions smaller than TARGET_PAGE_SIZE hw/arm/stellaris: Use HWADDR_PRIx to display register address hw/arm/stellaris: Fix gptm_write() error message hw/net/smc91c111: Use qemu_log_mask(UNIMP) instead of fprintf hw/net/smc91c111: Use qemu_log_mask(GUEST_ERROR) instead of hw_error hw/net/stellaris_enet: Use qemu_log_mask(GUEST_ERROR) instead of hw_error hw/net/stellaris_enet: Fix a typo hw/arm/stellaris: Use qemu_log_mask(UNIMP) instead of fprintf hw/arm/omap: Use qemu_log_mask(GUEST_ERROR) instead of fprintf hw/arm/omap1: Use qemu_log_mask(GUEST_ERROR) instead of fprintf hw/i2c/omap_i2c: Use qemu_log_mask(UNIMP) instead of fprintf ... Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw/misc')
-rw-r--r--hw/misc/aspeed_scu.c106
1 files changed, 106 insertions, 0 deletions
diff --git a/hw/misc/aspeed_scu.c b/hw/misc/aspeed_scu.c
index 5931501..59333b5 100644
--- a/hw/misc/aspeed_scu.c
+++ b/hw/misc/aspeed_scu.c
@@ -168,6 +168,27 @@ static uint32_t aspeed_scu_get_random(void)
return num;
}
+static void aspeed_scu_set_apb_freq(AspeedSCUState *s)
+{
+ uint32_t apb_divider;
+
+ switch (s->silicon_rev) {
+ case AST2400_A0_SILICON_REV:
+ case AST2400_A1_SILICON_REV:
+ apb_divider = 2;
+ break;
+ case AST2500_A0_SILICON_REV:
+ case AST2500_A1_SILICON_REV:
+ apb_divider = 4;
+ break;
+ default:
+ g_assert_not_reached();
+ }
+
+ s->apb_freq = s->hpll / (SCU_CLK_GET_PCLK_DIV(s->regs[CLK_SEL]) + 1)
+ / apb_divider;
+}
+
static uint64_t aspeed_scu_read(void *opaque, hwaddr offset, unsigned size)
{
AspeedSCUState *s = ASPEED_SCU(opaque);
@@ -222,6 +243,10 @@ static void aspeed_scu_write(void *opaque, hwaddr offset, uint64_t data,
case PROT_KEY:
s->regs[reg] = (data == ASPEED_SCU_PROT_KEY) ? 1 : 0;
return;
+ case CLK_SEL:
+ s->regs[reg] = data;
+ aspeed_scu_set_apb_freq(s);
+ break;
case FREQ_CNTR_EVAL:
case VGA_SCRATCH1 ... VGA_SCRATCH8:
@@ -247,19 +272,93 @@ static const MemoryRegionOps aspeed_scu_ops = {
.valid.unaligned = false,
};
+static uint32_t aspeed_scu_get_clkin(AspeedSCUState *s)
+{
+ if (s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN) {
+ return 25000000;
+ } else if (s->hw_strap1 & SCU_HW_STRAP_CLK_48M_IN) {
+ return 48000000;
+ } else {
+ return 24000000;
+ }
+}
+
+/*
+ * Strapped frequencies for the AST2400 in MHz. They depend on the
+ * clkin frequency.
+ */
+static const uint32_t hpll_ast2400_freqs[][4] = {
+ { 384, 360, 336, 408 }, /* 24MHz or 48MHz */
+ { 400, 375, 350, 425 }, /* 25MHz */
+};
+
+static uint32_t aspeed_scu_calc_hpll_ast2400(AspeedSCUState *s)
+{
+ uint32_t hpll_reg = s->regs[HPLL_PARAM];
+ uint8_t freq_select;
+ bool clk_25m_in;
+
+ if (hpll_reg & SCU_AST2400_H_PLL_OFF) {
+ return 0;
+ }
+
+ if (hpll_reg & SCU_AST2400_H_PLL_PROGRAMMED) {
+ uint32_t multiplier = 1;
+
+ if (!(hpll_reg & SCU_AST2400_H_PLL_BYPASS_EN)) {
+ uint32_t n = (hpll_reg >> 5) & 0x3f;
+ uint32_t od = (hpll_reg >> 4) & 0x1;
+ uint32_t d = hpll_reg & 0xf;
+
+ multiplier = (2 - od) * ((n + 2) / (d + 1));
+ }
+
+ return s->clkin * multiplier;
+ }
+
+ /* HW strapping */
+ clk_25m_in = !!(s->hw_strap1 & SCU_HW_STRAP_CLK_25M_IN);
+ freq_select = SCU_AST2400_HW_STRAP_GET_H_PLL_CLK(s->hw_strap1);
+
+ return hpll_ast2400_freqs[clk_25m_in][freq_select] * 1000000;
+}
+
+static uint32_t aspeed_scu_calc_hpll_ast2500(AspeedSCUState *s)
+{
+ uint32_t hpll_reg = s->regs[HPLL_PARAM];
+ uint32_t multiplier = 1;
+
+ if (hpll_reg & SCU_H_PLL_OFF) {
+ return 0;
+ }
+
+ if (!(hpll_reg & SCU_H_PLL_BYPASS_EN)) {
+ uint32_t p = (hpll_reg >> 13) & 0x3f;
+ uint32_t m = (hpll_reg >> 5) & 0xff;
+ uint32_t n = hpll_reg & 0x1f;
+
+ multiplier = ((m + 1) / (n + 1)) / (p + 1);
+ }
+
+ return s->clkin * multiplier;
+}
+
static void aspeed_scu_reset(DeviceState *dev)
{
AspeedSCUState *s = ASPEED_SCU(dev);
const uint32_t *reset;
+ uint32_t (*calc_hpll)(AspeedSCUState *s);
switch (s->silicon_rev) {
case AST2400_A0_SILICON_REV:
case AST2400_A1_SILICON_REV:
reset = ast2400_a0_resets;
+ calc_hpll = aspeed_scu_calc_hpll_ast2400;
break;
case AST2500_A0_SILICON_REV:
case AST2500_A1_SILICON_REV:
reset = ast2500_a1_resets;
+ calc_hpll = aspeed_scu_calc_hpll_ast2500;
break;
default:
g_assert_not_reached();
@@ -270,6 +369,13 @@ static void aspeed_scu_reset(DeviceState *dev)
s->regs[HW_STRAP1] = s->hw_strap1;
s->regs[HW_STRAP2] = s->hw_strap2;
s->regs[PROT_KEY] = s->hw_prot_key;
+
+ /*
+ * All registers are set. Now compute the frequencies of the main clocks
+ */
+ s->clkin = aspeed_scu_get_clkin(s);
+ s->hpll = calc_hpll(s);
+ aspeed_scu_set_apb_freq(s);
}
static uint32_t aspeed_silicon_revs[] = {