* Re: [Qemu-devel] [PATCH 1/2] ARM: exynos4210: CMU support
[not found] ` <CAAu8pHsguU4BRDA9g3++x8JFo=C2SF3HK0--WFngz=96SV5y9A@mail.gmail.com>
@ 2012-07-02 9:53 ` Maksim Kozlov
0 siblings, 0 replies; only message in thread
From: Maksim Kozlov @ 2012-07-02 9:53 UTC (permalink / raw)
To: Blue Swirl; +Cc: peter.maydell, kyungmin.park, qemu-devel
Ok. Thanks for your remarks.
30.06.2012 00:26, Blue Swirl пишет:
> On Fri, Jun 29, 2012 at 4:04 PM, Maksim Kozlov<m.kozlov@samsung.com> wrote:
>> Add exynos4210 Clock Management Units emulation
>>
>> Signed-off-by: Maksim Kozlov<m.kozlov@samsung.com>
>> ---
>> hw/arm/Makefile.objs | 1 +
>> hw/exynos4210.c | 16 +
>> hw/exynos4210.h | 42 ++
>> hw/exynos4210_cmu.c | 1462 ++++++++++++++++++++++++++++++++++++++++++++++++++
>> 4 files changed, 1521 insertions(+), 0 deletions(-)
>> create mode 100644 hw/exynos4210_cmu.c
>>
>> diff --git a/hw/arm/Makefile.objs b/hw/arm/Makefile.objs
>> index 88ff47d..20d19f2 100644
>> --- a/hw/arm/Makefile.objs
>> +++ b/hw/arm/Makefile.objs
>> @@ -11,6 +11,7 @@ obj-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
>> obj-y += exynos4210_gic.o exynos4210_combiner.o exynos4210.o
>> obj-y += exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o
>> obj-y += exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o
>> +obj-y += exynos4210_cmu.o
>> obj-y += arm_l2x0.o
>> obj-y += arm_mptimer.o a15mpcore.o
>> obj-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
>> diff --git a/hw/exynos4210.c b/hw/exynos4210.c
>> index 9c20b3f..55b8e24 100644
>> --- a/hw/exynos4210.c
>> +++ b/hw/exynos4210.c
>> @@ -30,6 +30,13 @@
>>
>> #define EXYNOS4210_CHIPID_ADDR 0x10000000
>>
>> +/* CMUs */
>> +#define EXYNOS4210_CMU_LEFTBUS_BASE_ADDR 0x10034000
>> +#define EXYNOS4210_CMU_RIGHTBUS_BASE_ADDR 0x10038000
>> +#define EXYNOS4210_CMU_TOP_BASE_ADDR 0x1003C000
>> +#define EXYNOS4210_CMU_DMC_BASE_ADDR 0x10040000
>> +#define EXYNOS4210_CMU_CPU_BASE_ADDR 0x10044000
>> +
>> /* PWM */
>> #define EXYNOS4210_PWM_BASE_ADDR 0x139D0000
>>
>> @@ -250,6 +257,15 @@ Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
>> */
>> sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
>>
>> + /* CMUs */
>> + exynos4210_cmu_create(EXYNOS4210_CMU_LEFTBUS_BASE_ADDR,
>> + EXYNOS4210_CMU_LEFTBUS);
>> + exynos4210_cmu_create(EXYNOS4210_CMU_RIGHTBUS_BASE_ADDR,
>> + EXYNOS4210_CMU_RIGHTBUS);
>> + exynos4210_cmu_create(EXYNOS4210_CMU_TOP_BASE_ADDR, EXYNOS4210_CMU_TOP);
>> + exynos4210_cmu_create(EXYNOS4210_CMU_DMC_BASE_ADDR, EXYNOS4210_CMU_DMC);
>> + exynos4210_cmu_create(EXYNOS4210_CMU_CPU_BASE_ADDR, EXYNOS4210_CMU_CPU);
>> +
>> /* PWM */
>> sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
>> s->irq_table[exynos4210_get_irq(22, 0)],
>> diff --git a/hw/exynos4210.h b/hw/exynos4210.h
>> index 9b1ae4c..fbdff7a 100644
>> --- a/hw/exynos4210.h
>> +++ b/hw/exynos4210.h
>> @@ -123,6 +123,48 @@ void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
>> int ext);
>>
>> /*
>> + * Interface for exynos4210 Clock Management Units (CMUs)
>> + */
>> +typedef enum {
>> + UNSPECIFIED_CMU = -1,
>> + EXYNOS4210_CMU_LEFTBUS,
>> + EXYNOS4210_CMU_RIGHTBUS,
>> + EXYNOS4210_CMU_TOP,
>> + EXYNOS4210_CMU_DMC,
>> + EXYNOS4210_CMU_CPU,
>> + EXYNOS4210_CMU_NUMBER
>> +} Exynos4210Cmu;
>> +
>> +typedef enum {
>> + UNSPECIFIED_CLOCK,
>> + EXYNOS4210_XXTI,
>> + EXYNOS4210_XUSBXTI,
>> + EXYNOS4210_APLL,
>> + EXYNOS4210_MPLL,
>> + EXYNOS4210_SCLK_HDMI24M,
>> + EXYNOS4210_SCLK_USBPHY0,
>> + EXYNOS4210_SCLK_USBPHY1,
>> + EXYNOS4210_SCLK_HDMIPHY,
>> + EXYNOS4210_SCLK_APLL,
>> + EXYNOS4210_SCLK_MPLL,
>> + EXYNOS4210_ACLK_100,
>> + EXYNOS4210_SCLK_UART0,
>> + EXYNOS4210_SCLK_UART1,
>> + EXYNOS4210_SCLK_UART2,
>> + EXYNOS4210_SCLK_UART3,
>> + EXYNOS4210_SCLK_UART4,
>> + EXYNOS4210_CLOCKS_NUMBER
>> +} Exynos4210Clock;
>> +
>> +typedef void ClockChangeHandler(void *opaque);
>> +
>> +DeviceState *exynos4210_cmu_create(target_phys_addr_t addr, Exynos4210Cmu cmu);
>> +uint64_t exynos4210_cmu_get_rate(Exynos4210Clock clock_id);
>> +void exynos4210_register_clock_handler(ClockChangeHandler *func,
>> + Exynos4210Clock clock_id,
>> + void *opaque);
>> +
>> +/*
>> * exynos4210 UART
>> */
>> DeviceState *exynos4210_uart_create(target_phys_addr_t addr,
>> diff --git a/hw/exynos4210_cmu.c b/hw/exynos4210_cmu.c
>> new file mode 100644
>> index 0000000..f3e5a30
>> --- /dev/null
>> +++ b/hw/exynos4210_cmu.c
>> @@ -0,0 +1,1462 @@
>> +/*
>> + * exynos4210 Clock Management Units (CMUs) Emulation
>> + *
>> + * Copyright (C) 2011 Samsung Electronics Co Ltd.
>> + * Maksim Kozlov,<m.kozlov@samsung.com>
>> + *
>> + * This program is free software; you can redistribute it and/or modify it
>> + * under the terms of the GNU General Public License as published by the
>> + * Free Software Foundation; either version 2 of the License, or
>> + * (at your option) any later version.
>> + *
>> + * This program is distributed in the hope that it will be useful, but WITHOUT
>> + * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
>> + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
>> + * for more details.
>> + *
>> + * You should have received a copy of the GNU General Public License along
>> + * with this program; if not, see<http://www.gnu.org/licenses/>.
>> + *
>> + */
>> +
>> +#include "sysbus.h"
>> +
>> +#include "exynos4210.h"
>> +
>> +
>> +#define DEBUG_CMU 0
>> +#define DEBUG_CMU_EXTEND 0
>> +
>> +#if DEBUG_CMU || DEBUG_CMU_EXTEND
>> +
>> + #define PRINT_DEBUG(fmt, args...) \
>> + do { \
>> + fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
>> + } while (0)
>> +
>> + #define PRINT_DEBUG_SIMPLE(fmt, args...) \
>> + do { \
>> + fprintf(stderr, fmt, ## args); \
>> + } while (0)
>> +
>> +#if DEBUG_CMU_EXTEND
>> +
>> + #define PRINT_DEBUG_EXTEND(fmt, args...) \
>> + do { \
>> + fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
>> + } while (0)
>> +#else
>> + #define PRINT_DEBUG_EXTEND(fmt, args...) \
>> + do {} while (0)
>> +#endif /* EXTEND */
>> +
>> +#else
>> + #define PRINT_DEBUG(fmt, args...) \
>> + do {} while (0)
>> + #define PRINT_DEBUG_SIMPLE(fmt, args...) \
>> + do {} while (0)
>> + #define PRINT_DEBUG_EXTEND(fmt, args...) \
>> + do {} while (0)
>> +#endif
>> +
>> +#define PRINT_ERROR(fmt, args...) \
>> + do { \
>> + fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
>> + } while (0)
>> +
>> +
>> +
>> +/* function blocks */
>> +#define LEFTBUS_BLK 0x0
>> +#define RIGHTBUS_BLK 0x0
>> +#define TOP_BLK 0x10
>> +#define TOP0_BLK 0x10
>> +#define TOP1_BLK 0x14
>> +#define DMC_BLK 0x0
>> +#define DMC0_BLK 0x0
>> +#define DMC1_BLK 0x4
>> +#define CPU_BLK 0x0
>> +#define CPU0_BLK 0x0
>> +#define CPU1_BLK 0x4
>> +
>> +#define CAM_BLK 0x20
>> +#define TV_BLK 0x24
>> +#define MFC_BLK 0x28
>> +#define G3D_BLK 0x2C
>> +#define IMAGE_BLK 0x30
>> +#define LCD0_BLK 0x34
>> +#define LCD1_BLK 0x38
>> +#define MAUDIO_BLK 0x3C
>> +#define FSYS_BLK 0x40
>> +#define FSYS0_BLK 0x40
>> +#define FSYS1_BLK 0x44
>> +#define FSYS2_BLK 0x48
>> +#define FSYS3_BLK 0x4C
>> +#define GPS_BLK 0x4C /* CLK_GATE_IP_GPS in CMU_TOP */
>> +#define PERIL_BLK 0x50
>> +#define PERIL0_BLK 0x50
>> +#define PERIL1_BLK 0x54
>> +#define PERIL2_BLK 0x58
>> +#define PERIL3_BLK 0x5C
>> +#define PERIL4_BLK 0x60
>> +#define PERIR_BLK 0x60 /* CLK_GATE_IP_PERIR in CMU_TOP */
>> +#define PERIL5_BLK 0x64
>> +
>> +#define BLOCK_MASK 0xFF
>> +
>> +/* PLLs */
>> +/* located in CMU_CPU block */
>> +#define APLL 0x00
>> +#define MPLL 0x08
>> +/* located in CMU_TOP block */
>> +#define EPLL 0x10
>> +#define VPLL 0x20
>> +
>> +/* groups of registers */
>> +#define PLL_LOCK 0x000
>> +#define PLL_CON 0x100
>> +#define CLK_SRC 0x200
>> +#define CLK_SRC_MASK 0x300
>> +#define CLK_MUX_STAT 0x400
>> +#define CLK_DIV 0x500
>> +#define CLK_DIV_STAT 0x600
>> +#define CLK_GATE_SCLK 0x800
>> +#define CLK_GATE_IP 0x900
>> +
>> +#define GROUP_MASK 0xF00
>> +
>> +#define PLL_LOCK_(pll) (PLL_LOCK + pll)
>> +#define PLL_CON0_(pll) (PLL_CON + pll)
>> +#define PLL_CON1_(pll) (PLL_CON + pll + 4)
>> +
>> +#define CLK_SRC_(block) (CLK_SRC + block)
>> +#define CLK_SRC_MASK_(block) (CLK_SRC_MASK + block)
>> +#define CLK_MUX_STAT_(block) (CLK_MUX_STAT + block)
>> +#define CLK_DIV_(block) (CLK_DIV + block)
>> +#define CLKDIV2_RATIO 0x580 /* described for CMU_TOP only */
>> +#define CLK_DIV_STAT_(block) (CLK_DIV_STAT + block)
>> +#define CLKDIV2_STAT 0x680 /* described for CMU_TOP only */
>> +#define CLK_GATE_SCLK_(block) (CLK_GATE_SCLK + block)
>> +/* For CMU_LEFTBUS and CMU_RIGHTBUS, CLK_GATE_IP_XXX
>> + registers are located at 0x800. */
>> +#define CLK_GATE_IP_LR_BUS 0x800
>> +#define CLK_GATE_IP_(block) (CLK_GATE_IP + block)
>> +#define CLK_GATE_BLOCK 0x970 /* described for CMU_TOP only */
>> +#define CLKOUT_CMU 0xA00
>> +#define CLKOUT_CMU_DIV_STAT 0xA04
>> +
>> +/*
>> + * registers which are located outside of 0xAFF region
>> + */
>> +/* CMU_DMC */
>> +#define DCGIDX_MAP0 0x01000
>> +#define DCGIDX_MAP1 0x01004
>> +#define DCGIDX_MAP2 0x01008
>> +#define DCGPERF_MAP0 0x01020
>> +#define DCGPERF_MAP1 0x01024
>> +#define DVCIDX_MAP 0x01040
>> +#define FREQ_CPU 0x01060
>> +#define FREQ_DPM 0x01064
>> +#define DVSEMCLK_EN 0x01080
>> +#define MAXPERF 0x01084
>> +/* CMU_CPU */
>> +#define ARMCLK_STOPCTRL 0x01000
>> +#define ATCLK_STOPCTRL 0x01004
>> +#define PARITYFAIL_STATUS 0x01010
>> +#define PARITYFAIL_CLEAR 0x01014
>> +#define PWR_CTRL 0x01020
>> +#define APLL_CON0_L8 0x01100
>> +#define APLL_CON0_L7 0x01104
>> +#define APLL_CON0_L6 0x01108
>> +#define APLL_CON0_L5 0x0110C
>> +#define APLL_CON0_L4 0x01110
>> +#define APLL_CON0_L3 0x01114
>> +#define APLL_CON0_L2 0x01118
>> +#define APLL_CON0_L1 0x0111C
>> +#define IEM_CONTROL 0x01120
>> +#define APLL_CON1_L8 0x01200
>> +#define APLL_CON1_L7 0x01204
>> +#define APLL_CON1_L6 0x01208
>> +#define APLL_CON1_L5 0x0120C
>> +#define APLL_CON1_L4 0x01210
>> +#define APLL_CON1_L3 0x01214
>> +#define APLL_CON1_L2 0x01218
>> +#define APLL_CON1_L1 0x0121C
>> +#define CLKDIV_IEM_L8 0x01300
>> +#define CLKDIV_IEM_L7 0x01304
>> +#define CLKDIV_IEM_L6 0x01308
>> +#define CLKDIV_IEM_L5 0x0130C
>> +#define CLKDIV_IEM_L4 0x01310
>> +#define CLKDIV_IEM_L3 0x01314
>> +#define CLKDIV_IEM_L2 0x01318
>> +#define CLKDIV_IEM_L1 0x0131C
>> +
>> +#define EXTENDED_REGION_MASK 0x1000
>> +#define EXTENDED_REGISTER_MASK 0xFFF
>> +
>> +typedef struct {
>> + const char *name; /* for debugging */
>> + uint32_t offset;
>> + uint32_t reset_value;
>> +} Exynos4210CmuReg;
>> +
>> +
>> +static Exynos4210CmuReg exynos4210_cmu_leftbus_regs[] = {
>
> All these structures could be const, I think. I hope you are not
> attempting to use static state for the actual register contents.
>
>> + /* CMU_LEFTBUS registers */
>> + { "CLK_SRC_LEFTBUS", CLK_SRC_(LEFTBUS_BLK), 0x00000000 },
>> + { "CLK_MUX_STAT_LEFTBUS", CLK_MUX_STAT_(LEFTBUS_BLK), 0x00000001 },
>> + { "CLK_DIV_LEFTBUS", CLK_DIV_(LEFTBUS_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_LEFTBUS", CLK_DIV_STAT_(LEFTBUS_BLK), 0x00000000 },
>> + { "CLK_GATE_IP_LEFTBUS", CLK_GATE_IP_LR_BUS, 0xFFFFFFFF },
>> + { "CLKOUT_CMU_LEFTBUS", CLKOUT_CMU, 0x00010000 },
>> + { "CLKOUT_CMU_LEFTBUS_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000 },
>> +};
>> +
>> +static Exynos4210CmuReg exynos4210_cmu_rightbus_regs[] = {
>> + /* CMU_RIGHTBUS registers */
>> + { "CLK_SRC_RIGHTBUS", CLK_SRC_(RIGHTBUS_BLK), 0x00000000 },
>> + { "CLK_MUX_STAT_RIGHTBUS", CLK_MUX_STAT_(RIGHTBUS_BLK), 0x00000001 },
>> + { "CLK_DIV_RIGHTBUS", CLK_DIV_(RIGHTBUS_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_RIGHTBUS", CLK_DIV_STAT_(RIGHTBUS_BLK), 0x00000000 },
>> + { "CLK_GATE_IP_RIGHTBUS", CLK_GATE_IP_LR_BUS, 0xFFFFFFFF },
>> + { "CLKOUT_CMU_RIGHTBUS", CLKOUT_CMU, 0x00010000 },
>> + { "CLKOUT_CMU_RIGHTBUS_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000 },
>> +};
>> +
>> +static Exynos4210CmuReg exynos4210_cmu_top_regs[] = {
>> + /* CMU_TOP registers */
>> + { "EPLL_LOCK", PLL_LOCK_(EPLL), 0x00000FFF },
>> + { "VPLL_LOCK", PLL_LOCK_(VPLL), 0x00000FFF },
>> + { "EPLL_CON0", PLL_CON0_(EPLL), 0x00300301 },
>> + { "EPLL_CON1", PLL_CON1_(EPLL), 0x00000000 },
>> + { "VPLL_CON0", PLL_CON0_(VPLL), 0x00240201 },
>> + { "VPLL_CON1", PLL_CON1_(VPLL), 0x66010464 },
>> + { "CLK_SRC_TOP0", CLK_SRC_(TOP0_BLK), 0x00000000 },
>> + { "CLK_SRC_TOP1", CLK_SRC_(TOP1_BLK), 0x00000000 },
>> + { "CLK_SRC_CAM", CLK_SRC_(CAM_BLK), 0x11111111 },
>> + { "CLK_SRC_TV", CLK_SRC_(TV_BLK), 0x00000000 },
>> + { "CLK_SRC_MFC", CLK_SRC_(MFC_BLK), 0x00000000 },
>> + { "CLK_SRC_G3D", CLK_SRC_(G3D_BLK), 0x00000000 },
>> + { "CLK_SRC_IMAGE", CLK_SRC_(IMAGE_BLK), 0x00000000 },
>> + { "CLK_SRC_LCD0", CLK_SRC_(LCD0_BLK), 0x00001111 },
>> + { "CLK_SRC_LCD1", CLK_SRC_(LCD1_BLK), 0x00001111 },
>> + { "CLK_SRC_MAUDIO", CLK_SRC_(MAUDIO_BLK), 0x00000005 },
>> + { "CLK_SRC_FSYS", CLK_SRC_(FSYS_BLK), 0x00011111 },
>> + { "CLK_SRC_PERIL0", CLK_SRC_(PERIL0_BLK), 0x00011111 },
>> + { "CLK_SRC_PERIL1", CLK_SRC_(PERIL1_BLK), 0x01110055 },
>> + { "CLK_SRC_MASK_TOP", CLK_SRC_MASK_(TOP_BLK), 0x00000001 },
>> + { "CLK_SRC_MASK_CAM", CLK_SRC_MASK_(CAM_BLK), 0x11111111 },
>> + { "CLK_SRC_MASK_TV", CLK_SRC_MASK_(TV_BLK), 0x00000111 },
>> + { "CLK_SRC_MASK_LCD0", CLK_SRC_MASK_(LCD0_BLK), 0x00001111 },
>> + { "CLK_SRC_MASK_LCD1", CLK_SRC_MASK_(LCD1_BLK), 0x00001111 },
>> + { "CLK_SRC_MASK_MAUDIO", CLK_SRC_MASK_(MAUDIO_BLK), 0x00000001 },
>> + { "CLK_SRC_MASK_FSYS", CLK_SRC_MASK_(FSYS_BLK), 0x01011111 },
>> + { "CLK_SRC_MASK_PERIL0", CLK_SRC_MASK_(PERIL0_BLK), 0x00011111 },
>> + { "CLK_SRC_MASK_PERIL1", CLK_SRC_MASK_(PERIL1_BLK), 0x01110111 },
>> + { "CLK_MUX_STAT_TOP", CLK_MUX_STAT_(TOP_BLK), 0x11111111 },
>> + { "CLK_MUX_STAT_MFC", CLK_MUX_STAT_(MFC_BLK), 0x00000111 },
>> + { "CLK_MUX_STAT_G3D", CLK_MUX_STAT_(G3D_BLK), 0x00000111 },
>> + { "CLK_MUX_STAT_IMAGE", CLK_MUX_STAT_(IMAGE_BLK), 0x00000111 },
>> + { "CLK_DIV_TOP", CLK_DIV_(TOP_BLK), 0x00000000 },
>> + { "CLK_DIV_CAM", CLK_DIV_(CAM_BLK), 0x00000000 },
>> + { "CLK_DIV_TV", CLK_DIV_(TV_BLK), 0x00000000 },
>> + { "CLK_DIV_MFC", CLK_DIV_(MFC_BLK), 0x00000000 },
>> + { "CLK_DIV_G3D", CLK_DIV_(G3D_BLK), 0x00000000 },
>> + { "CLK_DIV_IMAGE", CLK_DIV_(IMAGE_BLK), 0x00000000 },
>> + { "CLK_DIV_LCD0", CLK_DIV_(LCD0_BLK), 0x00700000 },
>> + { "CLK_DIV_LCD1", CLK_DIV_(LCD1_BLK), 0x00700000 },
>> + { "CLK_DIV_MAUDIO", CLK_DIV_(MAUDIO_BLK), 0x00000000 },
>> + { "CLK_DIV_FSYS0", CLK_DIV_(FSYS0_BLK), 0x00B00000 },
>> + { "CLK_DIV_FSYS1", CLK_DIV_(FSYS1_BLK), 0x00000000 },
>> + { "CLK_DIV_FSYS2", CLK_DIV_(FSYS2_BLK), 0x00000000 },
>> + { "CLK_DIV_FSYS3", CLK_DIV_(FSYS3_BLK), 0x00000000 },
>> + { "CLK_DIV_PERIL0", CLK_DIV_(PERIL0_BLK), 0x00000000 },
>> + { "CLK_DIV_PERIL1", CLK_DIV_(PERIL1_BLK), 0x00000000 },
>> + { "CLK_DIV_PERIL2", CLK_DIV_(PERIL2_BLK), 0x00000000 },
>> + { "CLK_DIV_PERIL3", CLK_DIV_(PERIL3_BLK), 0x00000000 },
>> + { "CLK_DIV_PERIL4", CLK_DIV_(PERIL4_BLK), 0x00000000 },
>> + { "CLK_DIV_PERIL5", CLK_DIV_(PERIL5_BLK), 0x00000000 },
>> + { "CLKDIV2_RATIO", CLKDIV2_RATIO, 0x11111111 },
>> + { "CLK_DIV_STAT_TOP", CLK_DIV_STAT_(TOP_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_CAM", CLK_DIV_STAT_(CAM_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_TV", CLK_DIV_STAT_(TV_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_MFC", CLK_DIV_STAT_(MFC_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_G3D", CLK_DIV_STAT_(G3D_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_IMAGE", CLK_DIV_STAT_(IMAGE_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_LCD0", CLK_DIV_STAT_(LCD0_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_LCD1", CLK_DIV_STAT_(LCD1_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_MAUDIO", CLK_DIV_STAT_(MAUDIO_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_FSYS0", CLK_DIV_STAT_(FSYS0_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_FSYS1", CLK_DIV_STAT_(FSYS1_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_FSYS2", CLK_DIV_STAT_(FSYS2_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_FSYS3", CLK_DIV_STAT_(FSYS3_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_PERIL0", CLK_DIV_STAT_(PERIL0_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_PERIL1", CLK_DIV_STAT_(PERIL1_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_PERIL2", CLK_DIV_STAT_(PERIL2_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_PERIL3", CLK_DIV_STAT_(PERIL3_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_PERIL4", CLK_DIV_STAT_(PERIL4_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_PERIL5", CLK_DIV_STAT_(PERIL5_BLK), 0x00000000 },
>> + { "CLKDIV2_STAT", CLKDIV2_STAT, 0x00000000 },
>> + { "CLK_GATE_SCLK_CAM", CLK_GATE_SCLK_(CAM_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_CAM", CLK_GATE_IP_(CAM_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_TV", CLK_GATE_IP_(TV_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_MFC", CLK_GATE_IP_(MFC_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_G3D", CLK_GATE_IP_(G3D_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_IMAGE", CLK_GATE_IP_(IMAGE_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_LCD0", CLK_GATE_IP_(LCD0_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_LCD1", CLK_GATE_IP_(LCD1_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_FSYS", CLK_GATE_IP_(FSYS_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_GPS", CLK_GATE_IP_(GPS_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_PERIL", CLK_GATE_IP_(PERIL_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_PERIR", CLK_GATE_IP_(PERIR_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_BLOCK", CLK_GATE_BLOCK, 0xFFFFFFFF },
>> + { "CLKOUT_CMU_TOP", CLKOUT_CMU, 0x00010000 },
>> + { "CLKOUT_CMU_TOP_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000 },
>> +};
>> +
>> +static Exynos4210CmuReg exynos4210_cmu_dmc_regs[] = {
>> + /* CMU_DMC registers */
>> + { "CLK_SRC_DMC", CLK_SRC_(DMC_BLK), 0x00010000 },
>> + { "CLK_SRC_MASK_DMC", CLK_SRC_MASK_(DMC_BLK), 0x00010000 },
>> + { "CLK_MUX_STAT_DMC", CLK_MUX_STAT_(DMC_BLK), 0x11100110 },
>> + { "CLK_DIV_DMC0", CLK_DIV_(DMC0_BLK), 0x00000000 },
>> + { "CLK_DIV_DMC1", CLK_DIV_(DMC1_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_DMC0", CLK_DIV_STAT_(DMC0_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_DMC1", CLK_DIV_STAT_(DMC1_BLK), 0x00000000 },
>> + { "CLK_GATE_IP_DMC", CLK_GATE_IP_(DMC_BLK), 0xFFFFFFFF },
>> + { "CLKOUT_CMU_DMC", CLKOUT_CMU, 0x00010000 },
>> + { "CLKOUT_CMU_DMC_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000 },
>> + { "DCGIDX_MAP0", DCGIDX_MAP0, 0xFFFFFFFF },
>> + { "DCGIDX_MAP1", DCGIDX_MAP1, 0xFFFFFFFF },
>> + { "DCGIDX_MAP2", DCGIDX_MAP2, 0xFFFFFFFF },
>> + { "DCGPERF_MAP0", DCGPERF_MAP0, 0xFFFFFFFF },
>> + { "DCGPERF_MAP1", DCGPERF_MAP1, 0xFFFFFFFF },
>> + { "DVCIDX_MAP", DVCIDX_MAP, 0xFFFFFFFF },
>> + { "FREQ_CPU", FREQ_CPU, 0x00000000 },
>> + { "FREQ_DPM", FREQ_DPM, 0x00000000 },
>> + { "DVSEMCLK_EN", DVSEMCLK_EN, 0x00000000 },
>> + { "MAXPERF", MAXPERF, 0x00000000 },
>> +};
>> +
>> +static Exynos4210CmuReg exynos4210_cmu_cpu_regs[] = {
>> + /* CMU_CPU registers */
>> + { "APLL_LOCK", PLL_LOCK_(APLL), 0x00000FFF },
>> + { "MPLL_LOCK", PLL_LOCK_(MPLL), 0x00000FFF },
>> + { "APLL_CON0", PLL_CON0_(APLL), 0x00C80601 },
>> + { "APLL_CON1", PLL_CON1_(APLL), 0x0000001C },
>> + { "MPLL_CON0", PLL_CON0_(MPLL), 0x00C80601 },
>> + { "MPLL_CON1", PLL_CON1_(MPLL), 0x0000001C },
>> + { "CLK_SRC_CPU", CLK_SRC_(CPU_BLK), 0x00000000 },
>> + { "CLK_MUX_STAT_CPU", CLK_MUX_STAT_(CPU_BLK), 0x00110101 },
>> + { "CLK_DIV_CPU0", CLK_DIV_(CPU0_BLK), 0x00000000 },
>> + { "CLK_DIV_CPU1", CLK_DIV_(CPU1_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_CPU0", CLK_DIV_STAT_(CPU0_BLK), 0x00000000 },
>> + { "CLK_DIV_STAT_CPU1", CLK_DIV_STAT_(CPU1_BLK), 0x00000000 },
>> + { "CLK_GATE_SCLK_CPU", CLK_GATE_SCLK_(CPU_BLK), 0xFFFFFFFF },
>> + { "CLK_GATE_IP_CPU", CLK_GATE_IP_(CPU_BLK), 0xFFFFFFFF },
>> + { "CLKOUT_CMU_CPU", CLKOUT_CMU, 0x00010000 },
>> + { "CLKOUT_CMU_CPU_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000 },
>> + { "ARMCLK_STOPCTRL", ARMCLK_STOPCTRL, 0x00000044 },
>> + { "ATCLK_STOPCTRL", ATCLK_STOPCTRL, 0x00000044 },
>> + { "PARITYFAIL_STATUS", PARITYFAIL_STATUS, 0x00000000 },
>> + { "PARITYFAIL_CLEAR", PARITYFAIL_CLEAR, 0x00000000 },
>> + { "PWR_CTRL", PWR_CTRL, 0x00000033 },
>> + { "APLL_CON0_L8", APLL_CON0_L8, 0x00C80601 },
>> + { "APLL_CON0_L7", APLL_CON0_L7, 0x00C80601 },
>> + { "APLL_CON0_L6", APLL_CON0_L6, 0x00C80601 },
>> + { "APLL_CON0_L5", APLL_CON0_L5, 0x00C80601 },
>> + { "APLL_CON0_L4", APLL_CON0_L4, 0x00C80601 },
>> + { "APLL_CON0_L3", APLL_CON0_L3, 0x00C80601 },
>> + { "APLL_CON0_L2", APLL_CON0_L2, 0x00C80601 },
>> + { "APLL_CON0_L1", APLL_CON0_L1, 0x00C80601 },
>> + { "IEM_CONTROL", IEM_CONTROL, 0x00000000 },
>> + { "APLL_CON1_L8", APLL_CON1_L8, 0x00000000 },
>> + { "APLL_CON1_L7", APLL_CON1_L7, 0x00000000 },
>> + { "APLL_CON1_L6", APLL_CON1_L6, 0x00000000 },
>> + { "APLL_CON1_L5", APLL_CON1_L5, 0x00000000 },
>> + { "APLL_CON1_L4", APLL_CON1_L4, 0x00000000 },
>> + { "APLL_CON1_L3", APLL_CON1_L3, 0x00000000 },
>> + { "APLL_CON1_L2", APLL_CON1_L2, 0x00000000 },
>> + { "APLL_CON1_L1", APLL_CON1_L1, 0x00000000 },
>> + { "CLKDIV_IEM_L8", CLKDIV_IEM_L8, 0x00000000 },
>> + { "CLKDIV_IEM_L7", CLKDIV_IEM_L7, 0x00000000 },
>> + { "CLKDIV_IEM_L6", CLKDIV_IEM_L6, 0x00000000 },
>> + { "CLKDIV_IEM_L5", CLKDIV_IEM_L5, 0x00000000 },
>> + { "CLKDIV_IEM_L4", CLKDIV_IEM_L4, 0x00000000 },
>> + { "CLKDIV_IEM_L3", CLKDIV_IEM_L3, 0x00000000 },
>> + { "CLKDIV_IEM_L2", CLKDIV_IEM_L2, 0x00000000 },
>> + { "CLKDIV_IEM_L1", CLKDIV_IEM_L1, 0x00000000 },
>> +};
>> +
>> +#define EXYNOS4210_CMU_REGS_MEM_SIZE 0x4000
>> +
>> +/*
>> + * for indexing register in the uint32_t array
>> + *
>> + * 'reg' - register offset (see offsets definitions above)
>> + *
>> + */
>> +#define I_(reg) (reg / sizeof(uint32_t))
>> +
>> +#define XOM_0 1 /* Select XXTI (0) or XUSBXTI (1) base clock source */
>> +
>> +/*
>> + * Offsets in CLK_SRC_CPU register
>> + * for control MUXMPLL and MUXAPLL
>> + *
>> + * 0 = FINPLL, 1 = MOUTM(A)PLLFOUT
>> + */
>> +#define MUX_APLL_SEL_SHIFT 0
>> +#define MUX_MPLL_SEL_SHIFT 8
>> +#define MUX_CORE_SEL_SHIFT 16
>> +#define MUX_HPM_SEL_SHIFT 20
>> +
>> +#define MUX_APLL_SEL (1<< MUX_APLL_SEL_SHIFT)
>> +#define MUX_MPLL_SEL (1<< MUX_MPLL_SEL_SHIFT)
>> +#define MUX_CORE_SEL (1<< MUX_CORE_SEL_SHIFT)
>> +#define MUX_HPM_SEL (1<< MUX_HPM_SEL_SHIFT)
>> +
>> +/* Offsets for fields in CLK_MUX_STAT_CPU register */
>> +#define APLL_SEL_SHIFT 0
>> +#define APLL_SEL_MASK 0x00000007
>> +#define MPLL_SEL_SHIFT 8
>> +#define MPLL_SEL_MASK 0x00000700
>> +#define CORE_SEL_SHIFT 16
>> +#define CORE_SEL_MASK 0x00070000
>> +#define HPM_SEL_SHIFT 20
>> +#define HPM_SEL_MASK 0x00700000
>> +
>> +
>> +/* Offsets for fields in<pll>_CON0 register */
>> +#define PLL_ENABLE_SHIFT 31
>> +#define PLL_ENABLE_MASK 0x80000000 /* [31] bit */
>> +#define PLL_LOCKED_MASK 0x20000000 /* [29] bit */
>> +#define PLL_MDIV_SHIFT 16
>> +#define PLL_MDIV_MASK 0x03FF0000 /* [25:16] bits */
>> +#define PLL_PDIV_SHIFT 8
>> +#define PLL_PDIV_MASK 0x00003F00 /* [13:8] bits */
>> +#define PLL_SDIV_SHIFT 0
>> +#define PLL_SDIV_MASK 0x00000007 /* [2:0] bits */
>> +
>> +/*
>> + * Offset in CLK_DIV_CPU0 register
>> + * for DIVAPLL clock divider ratio
>> + */
>> +#define APLL_RATIO_SHIFT 24
>> +#define APLL_RATIO_MASK 0x07000000 /* [26:24] bits */
>> +
>> +/*
>> + * Offset in CLK_DIV_TOP register
>> + * for DIVACLK_100 clock divider ratio
>> + */
>> +#define ACLK_100_RATIO_SHIFT 4
>> +#define ACLK_100_RATIO_MASK 0x000000f0 /* [7:4] bits */
>> +
>> +/* Offset in CLK_SRC_TOP0 register */
>> +#define MUX_ACLK_100_SEL_SHIFT 16
>> +
>> +/*
>> + * Offsets in CLK_SRC_PERIL0 register
>> + * for clock sources of UARTs
>> + */
>> +#define UART0_SEL_SHIFT 0
>> +#define UART1_SEL_SHIFT 4
>> +#define UART2_SEL_SHIFT 8
>> +#define UART3_SEL_SHIFT 12
>> +#define UART4_SEL_SHIFT 16
>> +/*
>> + * Offsets in CLK_DIV_PERIL0 register
>> + * for clock divider of UARTs
>> + */
>> +#define UART0_DIV_SHIFT 0
>> +#define UART1_DIV_SHIFT 4
>> +#define UART2_DIV_SHIFT 8
>> +#define UART3_DIV_SHIFT 12
>> +#define UART4_DIV_SHIFT 16
>> +
>> +#define SOURCES_NUMBER 9
>> +
>> +typedef struct ClockChangeEntry {
>> + QTAILQ_ENTRY(ClockChangeEntry) entry;
>> + ClockChangeHandler *func;
>> + void *opaque;
>> +} ClockChangeEntry;
>> +
>> +#define TYPE_EXYNOS4210_CMU "exynos4210.cmu"
>> +#define TYPE_EXYNOS4210_CLOCK "exynos4210.clock"
>> +
>> +typedef struct {
>> + const char *name;
>> + int32_t id;
>> + uint64_t rate;
>> +
>> + /* Current source clock */
>> + int32_t src_id;
>> + /*
>> + * Available sources. Their order must correspond to CLK_SRC_ register
>> + */
>> + int32_t src_ids[SOURCES_NUMBER];
>> +
>> + uint32_t src_reg; /* Offset of CLK_SRC_<*> register */
>> + uint32_t div_reg; /* Offset of CLK_DIV_<*> register */
>> +
>> + /*
>> + * Shift for MUX_<clk>_SEL value which is stored
>> + * in appropriate CLK_MUX_STAT_<cmu> register
>> + */
>> + uint8_t mux_shift;
>> +
>> + /*
>> + * Shift for<clk>_RATIO value which is stored
>> + * in appropriate CLK_DIV_<cmu> register
>> + */
>> + uint8_t div_shift;
>> +
>> + /* Which CMU controls this clock */
>> + int32_t cmu_id;
>> +
>> + QTAILQ_HEAD(, ClockChangeEntry) clock_change_handler;
>> +} Exynos4210ClockState;
>> +
>> +typedef struct {
>> + SysBusDevice busdev;
>> + MemoryRegion iomem;
>> +
>> + /* registers values */
>> + uint32_t reg[EXYNOS4210_CMU_REGS_MEM_SIZE / sizeof(uint32_t)];
>> +
>> + /* which CMU it is */
>> + Exynos4210Cmu cmu_id;
>> +
>> + /* registers information for debugging and resetting */
>> + Exynos4210CmuReg *regs;
>> + int regs_number;
>> +
>> + Exynos4210ClockState *clock;
>> + int clock_number; /* how many clocks are controlled by given CMU */
>> +} Exynos4210CmuState;
>> +
>> +
>> +/* Clocks from Clock Pads */
>> +/*
>> + * Two following clocks aren't controlled by any CMUs. These structures are
>> + * used directly from global space and their fields shouldn't be modified.
>> + */
>> +
>> +/* It should be used only for testing purposes. XOM_0 is 0 */
>> +static Exynos4210ClockState xxti = {
>> + .name = "XXTI",
>> + .id = EXYNOS4210_XXTI,
>> + .rate = 24000000,
>> + .cmu_id = UNSPECIFIED_CMU,
>> +};
>> +
>> +/* Main source. XOM_0 is 1 */
>> +static Exynos4210ClockState xusbxti = {
>> + .name = "XUSBXTI",
>> + .id = EXYNOS4210_XUSBXTI,
>> + .rate = 24000000,
>> + .cmu_id = UNSPECIFIED_CMU,
>> +};
>> +
>> +/* PLLs */
>> +
>> +static Exynos4210ClockState mpll = {
>> + .name = "MPLL",
>> + .id = EXYNOS4210_MPLL,
>> + .src_id = (XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI),
>> + .div_reg = PLL_CON0_(MPLL),
>> + .cmu_id = EXYNOS4210_CMU_CPU,
>> +};
>> +
>> +static Exynos4210ClockState apll = {
>> + .name = "APLL",
>> + .id = EXYNOS4210_APLL,
>> + .src_id = (XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI),
>> + .div_reg = PLL_CON0_(APLL),
>> + .cmu_id = EXYNOS4210_CMU_CPU,
>> +};
>> +
>> +
>> +/**/
>> +
>> +static Exynos4210ClockState sclk_hdmi24m = {
>> + .name = "SCLK_HDMI24M",
>> + .id = EXYNOS4210_SCLK_HDMI24M,
>> + .rate = 24000000,
>> + .cmu_id = UNSPECIFIED_CMU,
>> +};
>> +
>> +static Exynos4210ClockState sclk_usbphy0 = {
>> + .name = "SCLK_USBPHY0",
>> + .id = EXYNOS4210_SCLK_USBPHY0,
>> + .rate = 24000000,
>> + .cmu_id = UNSPECIFIED_CMU,
>> +};
>> +
>> +static Exynos4210ClockState sclk_usbphy1 = {
>> + .name = "SCLK_USBPHY1",
>> + .id = EXYNOS4210_SCLK_USBPHY1,
>> + .rate = 24000000,
>> + .cmu_id = UNSPECIFIED_CMU,
>> +};
>> +
>> +static Exynos4210ClockState sclk_hdmiphy = {
>> + .name = "SCLK_HDMIPHY",
>> + .id = EXYNOS4210_SCLK_HDMIPHY,
>> + .rate = 24000000,
>> + .cmu_id = UNSPECIFIED_CMU,
>> +};
>> +
>> +static Exynos4210ClockState sclk_mpll = {
>> + .name = "SCLK_MPLL",
>> + .id = EXYNOS4210_SCLK_MPLL,
>> + .src_ids = {XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI,
>> + EXYNOS4210_MPLL},
>> + .src_reg = CLK_SRC_(CPU_BLK),
>> + .mux_shift = MUX_MPLL_SEL_SHIFT,
>> + .cmu_id = EXYNOS4210_CMU_CPU,
>> +};
>> +
>> +static Exynos4210ClockState sclk_apll = {
>> + .name = "SCLK_APLL",
>> + .id = EXYNOS4210_SCLK_APLL,
>> + .src_ids = {XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI,
>> + EXYNOS4210_APLL},
>> + .src_reg = CLK_SRC_(CPU_BLK),
>> + .div_reg = CLK_DIV_(CPU0_BLK),
>> + .mux_shift = MUX_APLL_SEL_SHIFT,
>> + .div_shift = APLL_RATIO_SHIFT,
>> + .cmu_id = EXYNOS4210_CMU_CPU,
>> +};
>> +
>> +static Exynos4210ClockState aclk_100 = {
>> + .name = "ACLK_100",
>> + .id = EXYNOS4210_ACLK_100,
>> + .src_ids = {EXYNOS4210_SCLK_MPLL, EXYNOS4210_SCLK_APLL},
>> + .src_reg = CLK_SRC_(TOP0_BLK),
>> + .div_reg = CLK_DIV_(TOP_BLK),
>> + .mux_shift = MUX_ACLK_100_SEL_SHIFT,
>> + .div_shift = ACLK_100_RATIO_SHIFT,
>> + .cmu_id = EXYNOS4210_CMU_TOP,
>> +};
>> +
>> +static Exynos4210ClockState sclk_uart0 = {
>> + .name = "SCLK_UART0",
>> + .id = EXYNOS4210_SCLK_UART0,
>> + .src_ids = {EXYNOS4210_XXTI,
>> + EXYNOS4210_XUSBXTI,
>> + EXYNOS4210_SCLK_HDMI24M,
>> + EXYNOS4210_SCLK_USBPHY0,
>> + EXYNOS4210_SCLK_USBPHY1,
>> + EXYNOS4210_SCLK_HDMIPHY,
>> + EXYNOS4210_SCLK_MPLL},
>> + .src_reg = CLK_SRC_(PERIL0_BLK),
>> + .div_reg = CLK_DIV_(PERIL0_BLK),
>> + .mux_shift = UART0_SEL_SHIFT,
>> + .div_shift = UART0_DIV_SHIFT,
>> + .cmu_id = EXYNOS4210_CMU_TOP,
>> +};
>> +
>> +static Exynos4210ClockState sclk_uart1 = {
>> + .name = "SCLK_UART1",
>> + .id = EXYNOS4210_SCLK_UART1,
>> + .src_ids = {EXYNOS4210_XXTI,
>> + EXYNOS4210_XUSBXTI,
>> + EXYNOS4210_SCLK_HDMI24M,
>> + EXYNOS4210_SCLK_USBPHY0,
>> + EXYNOS4210_SCLK_USBPHY1,
>> + EXYNOS4210_SCLK_HDMIPHY,
>> + EXYNOS4210_SCLK_MPLL},
>> + .src_reg = CLK_SRC_(PERIL0_BLK),
>> + .div_reg = CLK_DIV_(PERIL0_BLK),
>> + .mux_shift = UART1_SEL_SHIFT,
>> + .div_shift = UART1_DIV_SHIFT,
>> + .cmu_id = EXYNOS4210_CMU_TOP,
>> +};
>> +
>> +static Exynos4210ClockState sclk_uart2 = {
>> + .name = "SCLK_UART2",
>> + .id = EXYNOS4210_SCLK_UART2,
>> + .src_ids = {EXYNOS4210_XXTI,
>> + EXYNOS4210_XUSBXTI,
>> + EXYNOS4210_SCLK_HDMI24M,
>> + EXYNOS4210_SCLK_USBPHY0,
>> + EXYNOS4210_SCLK_USBPHY1,
>> + EXYNOS4210_SCLK_HDMIPHY,
>> + EXYNOS4210_SCLK_MPLL},
>> + .src_reg = CLK_SRC_(PERIL0_BLK),
>> + .div_reg = CLK_DIV_(PERIL0_BLK),
>> + .mux_shift = UART2_SEL_SHIFT,
>> + .div_shift = UART2_DIV_SHIFT,
>> + .cmu_id = EXYNOS4210_CMU_TOP,
>> +};
>> +
>> +static Exynos4210ClockState sclk_uart3 = {
>> + .name = "SCLK_UART3",
>> + .id = EXYNOS4210_SCLK_UART3,
>> + .src_ids = {EXYNOS4210_XXTI,
>> + EXYNOS4210_XUSBXTI,
>> + EXYNOS4210_SCLK_HDMI24M,
>> + EXYNOS4210_SCLK_USBPHY0,
>> + EXYNOS4210_SCLK_USBPHY1,
>> + EXYNOS4210_SCLK_HDMIPHY,
>> + EXYNOS4210_SCLK_MPLL},
>> + .src_reg = CLK_SRC_(PERIL0_BLK),
>> + .div_reg = CLK_DIV_(PERIL0_BLK),
>> + .mux_shift = UART3_SEL_SHIFT,
>> + .div_shift = UART3_DIV_SHIFT,
>> + .cmu_id = EXYNOS4210_CMU_TOP,
>> +};
>> +
>> +static Exynos4210ClockState sclk_uart4 = {
>> + .name = "SCLK_UART4",
>> + .id = EXYNOS4210_SCLK_UART4,
>> + .src_ids = {EXYNOS4210_XXTI,
>> + EXYNOS4210_XUSBXTI,
>> + EXYNOS4210_SCLK_HDMI24M,
>> + EXYNOS4210_SCLK_USBPHY0,
>> + EXYNOS4210_SCLK_USBPHY1,
>> + EXYNOS4210_SCLK_HDMIPHY,
>> + EXYNOS4210_SCLK_MPLL},
>> + .src_reg = CLK_SRC_(PERIL0_BLK),
>> + .div_reg = CLK_DIV_(PERIL0_BLK),
>> + .mux_shift = UART4_SEL_SHIFT,
>> + .div_shift = UART4_DIV_SHIFT,
>> + .cmu_id = EXYNOS4210_CMU_TOP,
>> +};
>> +
>> +/*
>> + * This array must correspond to Exynos4210Clock enumerator
>> + * which is defined in exynos4210.h file
>> + *
>> + */
>> +static Exynos4210ClockState *exynos4210_clock[] = {
>> + NULL,
>> +&xxti,
>> +&xusbxti,
>> +&apll,
>> +&mpll,
>> +&sclk_hdmi24m,
>> +&sclk_usbphy0,
>> +&sclk_usbphy1,
>> +&sclk_hdmiphy,
>> +&sclk_apll,
>> +&sclk_mpll,
>> +&aclk_100,
>> +&sclk_uart0,
>> +&sclk_uart1,
>> +&sclk_uart2,
>> +&sclk_uart3,
>> +&sclk_uart4,
>> + NULL,
>> +};
>> +
>> +/*
>> + * This array must correspond to Exynos4210Cmu enumerator
>> + * which is defined in exynos4210.h file
>> + *
>> + */
>> +static char exynos4210_cmu_path[][13] = {
>
> 'const'
>
>> + "cmu_leftbus",
>> + "cmu_rightbus",
>> + "cmu_top",
>> + "cmu_dmc",
>> + "cmu_cpu",
>> +};
>> +
>> +#if DEBUG_CMU_EXTEND
>> +/* The only meaning of life - debugging. This function should be only used
>> + * inside PRINT_DEBUG_EXTEND macros
>> + */
>> +static const char *exynos4210_cmu_regname(Exynos4210CmuState *s,
>> + target_phys_addr_t offset)
>> +{
>> + int i;
>> +
>> + for (i = 0; i< s->regs_number; i++) {
>> + if (offset == s->regs[i].offset) {
>> + return s->regs[i].name;
>> + }
>> + }
>> +
>> + return NULL;
>> +}
>> +#endif
>> +
>> +
>> +static Exynos4210ClockState *exynos4210_clock_find(Exynos4210Clock clock_id)
>> +{
>> + int i;
>> + int cmu_id;
>> + Object *cmu;
>> + Exynos4210CmuState *s;
>> +
>> + cmu_id = exynos4210_clock[clock_id]->cmu_id;
>> +
>> + if (cmu_id == UNSPECIFIED_CMU) {
>> + for (i = 1; i< EXYNOS4210_CLOCKS_NUMBER; i++) {
>> + if (exynos4210_clock[i]->id == clock_id) {
>> +
>> + PRINT_DEBUG("Clock %s [%p] in CMU %d have been found\n",
>> + exynos4210_clock[i]->name,
>> + exynos4210_clock[i],
>> + cmu_id);
>> +
>> + return exynos4210_clock[i];
>> + }
>> + }
>> + }
>> +
>> + cmu = object_resolve_path(exynos4210_cmu_path[cmu_id], NULL);
>> + s = OBJECT_CHECK(Exynos4210CmuState, cmu, TYPE_EXYNOS4210_CMU);
>> +
>> + for (i = 0; i< s->clock_number; i++) {
>> + if (s->clock[i].id == clock_id) {
>> +
>> + PRINT_DEBUG("Clock %s [%p] in CMU %d have been found\n",
>> + s->clock[i].name,
>> +&s->clock[i],
>> + s->clock[i].cmu_id);
>> + return&s->clock[i];
>> + }
>> + }
>> +
>> + PRINT_ERROR("Clock %d not found\n", clock_id);
>> +
>> + return NULL;
>> +}
>> +
>> +
>> +void exynos4210_register_clock_handler(ClockChangeHandler *func,
>> + Exynos4210Clock clock_id, void *opaque)
>> +{
>> + ClockChangeEntry *cce = g_malloc0(sizeof(ClockChangeEntry));
>> + Exynos4210ClockState *clock = exynos4210_clock_find(clock_id);
>> +
>> + if (clock == NULL) {
>> + hw_error("We aren't be able to find clock %d\n", clock_id);
>> + } else if (clock->cmu_id == UNSPECIFIED_CMU) {
>> +
>> + PRINT_DEBUG("Clock %s never are changed. Handler won't be set.",
>> + exynos4210_clock[clock_id]->name);
>> +
>> + return;
>> + }
>> +
>> + cce->func = func;
>> + cce->opaque = opaque;
>> +
>> + QTAILQ_INSERT_TAIL(&clock->clock_change_handler, cce, entry);
>> +
>> + PRINT_DEBUG("For %s have been set handler [%p]\n", clock->name, cce->func);
>> +
>> + return;
>> +}
>> +
>> +uint64_t exynos4210_cmu_get_rate(Exynos4210Clock clock_id)
>> +{
>> + Exynos4210ClockState *clock = exynos4210_clock_find(clock_id);
>> +
>> + if (clock == NULL) {
>> + hw_error("We aren't be able to find clock %d\n", clock_id);
>> + }
>> +
>> + return clock->rate;
>> +}
>> +
>> +static void exynos4210_cmu_set_pll(void *opaque, Exynos4210ClockState *pll)
>> +{
>> + Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
>
> Useless cast.
>
>> + Exynos4210ClockState *source;
>> + target_phys_addr_t offset = pll->div_reg;
>> + ClockChangeEntry *cce;
>> + uint32_t pdiv, mdiv, sdiv, enable;
>> +
>> + source = exynos4210_clock_find(pll->src_id);
>> +
>> + if (source == NULL) {
>> + hw_error("We haven't find source clock %d (requested for %s)\n",
>> + pll->src_id, pll->name);
>> + }
>> +
>> + /*
>> + * FOUT = MDIV * FIN / (PDIV * 2^(SDIV-1))
>> + */
>> +
>> + enable = (s->reg[I_(offset)]& PLL_ENABLE_MASK)>> PLL_ENABLE_SHIFT;
>> + mdiv = (s->reg[I_(offset)]& PLL_MDIV_MASK)>> PLL_MDIV_SHIFT;
>> + pdiv = (s->reg[I_(offset)]& PLL_PDIV_MASK)>> PLL_PDIV_SHIFT;
>> + sdiv = (s->reg[I_(offset)]& PLL_SDIV_MASK)>> PLL_SDIV_SHIFT;
>> +
>> + if (source) {
>> + if (enable) {
>> + pll->rate = mdiv * source->rate / (pdiv * (1<< (sdiv-1)));
>> + } else {
>> + pll->rate = 0;
>> + }
>> + } else {
>> + hw_error("%s: Source undefined for %s\n", __FUNCTION__, pll->name);
>> + }
>> +
>> + QTAILQ_FOREACH(cce,&pll->clock_change_handler, entry) {
>> + cce->func(cce->opaque);
>> + }
>> +
>> + PRINT_DEBUG("%s rate: %llu\n", pll->name, pll->rate);
>> +
>> + s->reg[I_(offset)] |= PLL_LOCKED_MASK;
>> +}
>> +
>> +
>> +static void exynos4210_cmu_set_rate(void *opaque, Exynos4210Clock clock_id)
>> +{
>> + Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
>> + Exynos4210ClockState *clock = exynos4210_clock_find(clock_id);
>> + ClockChangeEntry *cce;
>> +
>> + if (clock == NULL) {
>> + hw_error("We haven't find source clock %d ", clock_id);
>> + }
>> +
>> + if ((clock->id == EXYNOS4210_MPLL) || (clock->id == EXYNOS4210_APLL)) {
>> +
>> + exynos4210_cmu_set_pll(s, clock);
>> +
>> + } else if ((clock->cmu_id != UNSPECIFIED_CMU)) {
>> +
>> + Exynos4210ClockState *source;
>> +
>> + uint32_t src_index = I_(clock->src_reg);
>> + uint32_t div_index = I_(clock->div_reg);
>> +
>> + clock->src_id = clock->src_ids[(s->reg[src_index]>>
>> + clock->mux_shift)& 0xf];
>> +
>> + source = exynos4210_clock_find(clock->src_id);
>> + if (source == NULL) {
>> + hw_error("We haven't find source clock %d (requested for %s)\n",
>> + clock->src_id, clock->name);
>> + }
>> +
>> + clock->rate = muldiv64(source->rate, 1,
>> + ((((clock->div_reg ? s->reg[div_index] : 0)>>
>> + clock->div_shift)& 0xf) + 1));
>> +
>> + QTAILQ_FOREACH(cce,&clock->clock_change_handler, entry) {
>> + cce->func(cce->opaque);
>> + }
>> +
>> + PRINT_DEBUG_EXTEND("SRC:<0x%05x> %s, SHIFT: %d\n",
>> + clock->src_reg,
>> + exynos4210_cmu_regname(s, clock->src_reg),
>> + clock->mux_shift);
>> +
>> + PRINT_DEBUG("%s [%s:%llu]: %llu\n",
>> + clock->name,
>> + source->name,
>> + (long long unsigned int)source->rate,
>> + (long long unsigned int)clock->rate);
>> + }
>> +}
>> +
>> +
>> +static uint64_t exynos4210_cmu_read(void *opaque, target_phys_addr_t offset,
>> + unsigned size)
>> +{
>> + Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
>> +
>> + if (offset> (EXYNOS4210_CMU_REGS_MEM_SIZE - sizeof(uint32_t))) {
>> + PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
>> + return 0;
>> + }
>> +
>> + if (offset& EXTENDED_REGION_MASK) {
>> + if (s->cmu_id == EXYNOS4210_CMU_DMC) {
>> + switch (offset& 0xFFF) {
>> + case DCGIDX_MAP0:
>> + case DCGIDX_MAP1:
>> + case DCGIDX_MAP2:
>> + case DCGPERF_MAP0:
>> + case DCGPERF_MAP1:
>> + case DVCIDX_MAP:
>> + case FREQ_CPU:
>> + case FREQ_DPM:
>> + case DVSEMCLK_EN:
>> + case MAXPERF:
>> + return s->reg[I_(offset)];
>> + default:
>> + PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
>> + return 0;
>> + }
>> + }
>> +
>> + if (s->cmu_id == EXYNOS4210_CMU_CPU) {
>> + switch (offset& 0xFFF) {
>> + case ARMCLK_STOPCTRL:
>> + case ATCLK_STOPCTRL:
>> + case PARITYFAIL_STATUS:
>> + case PARITYFAIL_CLEAR:
>> + case PWR_CTRL:
>> + case APLL_CON0_L8:
>> + case APLL_CON0_L7:
>> + case APLL_CON0_L6:
>> + case APLL_CON0_L5:
>> + case APLL_CON0_L4:
>> + case APLL_CON0_L3:
>> + case APLL_CON0_L2:
>> + case APLL_CON0_L1:
>> + case IEM_CONTROL:
>> + case APLL_CON1_L8:
>> + case APLL_CON1_L7:
>> + case APLL_CON1_L6:
>> + case APLL_CON1_L5:
>> + case APLL_CON1_L4:
>> + case APLL_CON1_L3:
>> + case APLL_CON1_L2:
>> + case APLL_CON1_L1:
>> + case CLKDIV_IEM_L8:
>> + case CLKDIV_IEM_L7:
>> + case CLKDIV_IEM_L6:
>> + case CLKDIV_IEM_L5:
>> + case CLKDIV_IEM_L4:
>> + case CLKDIV_IEM_L3:
>> + case CLKDIV_IEM_L2:
>> + case CLKDIV_IEM_L1:
>> + return s->reg[I_(offset)];
>> + default:
>> + PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
>> + return 0;
>> + }
>> + }
>> + }
>> +
>> + switch (offset& GROUP_MASK) {
>> + case PLL_LOCK:
>> + case PLL_CON:
>> + case CLK_SRC:
>> + case CLK_SRC_MASK:
>> + case CLK_MUX_STAT:
>> + case CLK_DIV:
>> + case CLK_DIV_STAT:
>> + case 0x700: /* Reserved */
>> + case CLK_GATE_SCLK: /* reserved? */
>> + case CLK_GATE_IP:
>> + case CLKOUT_CMU:
>> + return s->reg[I_(offset)];
>> + default:
>> + PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
>> + return 0;
>> + }
>> +
>> + PRINT_DEBUG_EXTEND("<0x%05x> %s -> %08x\n", offset,
>> + exynos4210_cmu_regname(s, offset), s->reg[I_(offset)]);
>> +}
>> +
>> +
>> +static void exynos4210_cmu_write(void *opaque, target_phys_addr_t offset,
>> + uint64_t val, unsigned size)
>> +{
>> + Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
>> + uint32_t group, block;
>> +
>> + group = offset& GROUP_MASK;
>> + block = offset& BLOCK_MASK;
>> +
>> + switch (group) {
>> + case PLL_LOCK:
>> + /* it's not necessary at this moment
>> + * TODO: do it
>> + */
>> + break;
>> + case PLL_CON:
>> + switch (block) {
>> + case APLL:
>> + {
>> + uint32_t pre_val = s->reg[I_(offset)];
>> + s->reg[I_(offset)] = val;
>> + val = (val& ~PLL_LOCKED_MASK) | (pre_val& PLL_LOCKED_MASK);
>> + s->reg[I_(offset)] = val;
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_APLL);
>> + break;
>> + }
>> + case MPLL:
>> + {
>> + uint32_t pre_val = s->reg[I_(offset)];
>> + s->reg[I_(offset)] = val;
>> + val = (val& ~PLL_LOCKED_MASK) | (pre_val& PLL_LOCKED_MASK);
>> + s->reg[I_(offset)] = val;
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_MPLL);
>> + break;
>> + }
>> + case CLK_SRC:
>> + switch (block) {
>> + case CPU_BLK:
>> + {
>> + uint32_t pre_val = s->reg[I_(offset)];
>> + s->reg[I_(offset)] = val;
>> +
>> + if (val& MUX_APLL_SEL) {
>> + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
>> + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(APLL_SEL_MASK)) |
>> + (2<< APLL_SEL_SHIFT);
>> +
>> + if ((pre_val& MUX_APLL_SEL) !=
>> + (s->reg[I_(offset)]& MUX_APLL_SEL)) {
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_APLL);
>> + }
>> +
>> + } else {
>> + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
>> + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(APLL_SEL_MASK)) |
>> + (1<< APLL_SEL_SHIFT);
>> +
>> + if ((pre_val& MUX_APLL_SEL) !=
>> + (s->reg[I_(offset)]& MUX_APLL_SEL)) {
>> + exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_XUSBXTI :
>> + EXYNOS4210_XXTI);
>> + }
>> + }
>> +
>> +
>> + if (val& MUX_MPLL_SEL) {
>> + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
>> + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(MPLL_SEL_MASK)) |
>> + (2<< MPLL_SEL_SHIFT);
>> +
>> + if ((pre_val& MUX_MPLL_SEL) !=
>> + (s->reg[I_(offset)]& MUX_MPLL_SEL)) {
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_MPLL);
>> + }
>> +
>> + } else {
>> + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
>> + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(MPLL_SEL_MASK)) |
>> + (1<< MPLL_SEL_SHIFT);
>> +
>> + if ((pre_val& MUX_MPLL_SEL) !=
>> + (s->reg[I_(offset)]& MUX_MPLL_SEL)) {
>> + exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_XUSBXTI :
>> + EXYNOS4210_XXTI);
>> + }
>> + }
>> +
>> + if (val& MUX_CORE_SEL) {
>> + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
>> + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(CORE_SEL_MASK)) |
>> + (2<< CORE_SEL_SHIFT);
>> +
>> + if ((pre_val& MUX_CORE_SEL) !=
>> + (s->reg[I_(offset)]& MUX_CORE_SEL)) {
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPLL);
>> + }
>> +
>> + } else {
>> + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
>> + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(CORE_SEL_MASK)) |
>> + (1<< CORE_SEL_SHIFT);
>> +
>> + if ((pre_val& MUX_CORE_SEL) !=
>> + (s->reg[I_(offset)]& MUX_CORE_SEL)) {
>> + exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_XUSBXTI :
>> + EXYNOS4210_XXTI);
>> + }
>> + }
>> +
>> + if (val& MUX_HPM_SEL) {
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPLL);
>> + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
>> + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(HPM_SEL_MASK)) |
>> + (2<< HPM_SEL_SHIFT);
>> +
>> + if ((pre_val& MUX_HPM_SEL) !=
>> + (s->reg[I_(offset)]& MUX_HPM_SEL)) {
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPLL);
>> + }
>> +
>> + } else {
>> + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
>> + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(HPM_SEL_MASK)) |
>> + (1<< HPM_SEL_SHIFT);
>> +
>> + if ((pre_val& MUX_HPM_SEL) !=
>> + (s->reg[I_(offset)]& MUX_HPM_SEL)) {
>> + exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_XUSBXTI :
>> + EXYNOS4210_XXTI);
>> + }
>> + }
>> + }
>> + break;
>> + case TOP0_BLK:
>> + s->reg[I_(offset)] = val;
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_ACLK_100);
>> + break;
>> + default:
>> + PRINT_ERROR("Unknown functional block: 0x%x\n", (int)block);
>> + }
>> + break;
>> + case CLK_SRC_MASK:
>> + break;
>> + case CLK_MUX_STAT:
>> + break;
>> + case CLK_DIV:
>> + switch (block) {
>> + case TOP_BLK:
>> + s->reg[I_(offset)] = val;
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_ACLK_100);
>> + break;
>> + case CPU0_BLK:
>> + s->reg[I_(offset)] = val;
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_APLL);
>> + exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPLL);
>> + break;
>> + }
>> + case CLK_DIV_STAT: /* CLK_DIV_STAT */
>> + case 0x700: /* Reserved */
>> + case CLK_GATE_SCLK: /* reserved? */
>> + case CLK_GATE_IP:
>> + case CLKOUT_CMU:
>> + break;
>> + default:
>> + PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
>> + }
>> +}
>> +
>> +static const MemoryRegionOps exynos4210_cmu_ops = {
>> + .read = exynos4210_cmu_read,
>> + .write = exynos4210_cmu_write,
>> + .endianness = DEVICE_NATIVE_ENDIAN,
>> +};
>> +
>> +static void clock_rate_changed(void *opaque)
>> +{
>> + Exynos4210ClockState *cs = (Exynos4210ClockState *)opaque;
>> + Object *cmu = object_resolve_path(exynos4210_cmu_path[cs->cmu_id], NULL);
>> + Exynos4210CmuState *s = OBJECT_CHECK(Exynos4210CmuState, cmu,
>> + TYPE_EXYNOS4210_CMU);
>> +
>> + PRINT_DEBUG("Clock %s was changed\n", cs->name);
>> +
>> + exynos4210_cmu_set_rate(s, cs->id);
>> +
>> +}
>> +
>> +static void exynos4210_cmu_reset(DeviceState *dev)
>> +{
>> + Exynos4210CmuState *s = OBJECT_CHECK(Exynos4210CmuState, OBJECT(dev),
>> + TYPE_EXYNOS4210_CMU);
>> + int i, j;
>> + uint32_t index = 0;
>> +
>> + for (i = 0; i< s->regs_number; i++) {
>> + index = (s->regs[i].offset) / sizeof(uint32_t);
>> + s->reg[index] = s->regs[i].reset_value;
>> + }
>> +
>> + for (i = 0; i< s->clock_number; i++) {
>> +
>> + for (j = 0; j< SOURCES_NUMBER; j++) {
>> +
>> + if (s->clock[i].src_ids[j] == UNSPECIFIED_CLOCK) {
>> +
>> + if (j == 0) {
>> + /*
>> + * we have empty '.sources[]' array
>> + */
>> + if (s->clock[i].src_id != UNSPECIFIED_CLOCK) {
>> +
>> + s->clock[i].src_ids[j] = s->clock[i].src_id;
>> +
>> + } else {
>> +
>> + if (s->clock[i].cmu_id != UNSPECIFIED_CMU) {
>> + /*
>> + * We haven't any defined sources for this clock.
>> + * Error during definition of appropriate clock
>> + * structure
>> + */
>> + hw_error("exynos4210_cmu_reset:"
>> + "There aren't any sources for %s clock!\n",
>> + s->clock[i].name);
>> + } else {
>> + /*
>> + * we don't need any sources for this clock
>> + * because it's a root clock
>> + */
>> + break;
>> + }
>> + }
>> + } else {
>> + break; /* leave because there are no more sources */
>> + }
>> + } /* src_ids[j] == UNSPECIFIED_CLOCK */
>> +
>> + Exynos4210ClockState *source =
>> + exynos4210_clock_find(s->clock[i].src_ids[j]);
>> +
>> + if (source == NULL) {
>> + hw_error("We aren't be able to find source clock %d "
>> + "(requested for %s)\n",
>> + s->clock[i].src_ids[j], s->clock[i].name);
>> + }
>> +
>> + if (source->cmu_id != UNSPECIFIED_CMU) {
>> +
>> + exynos4210_register_clock_handler(clock_rate_changed,
>> + s->clock[i].src_ids[j],&s->clock[i]);
>> + }
>> + } /* SOURCES_NUMBER */
>> +
>> + exynos4210_cmu_set_rate(s, s->clock[i].id);
>> + }
>> +
>> + PRINT_DEBUG("CMU %d reset completed\n", s->cmu_id);
>> +}
>> +
>> +static const VMStateDescription vmstate_exynos4210_clock = {
>> + .name = TYPE_EXYNOS4210_CLOCK,
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .minimum_version_id_old = 1,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_UINT64(rate, Exynos4210ClockState),
>> + VMSTATE_INT32(src_id, Exynos4210ClockState),
>> + VMSTATE_INT32_ARRAY(src_ids, Exynos4210ClockState, SOURCES_NUMBER),
>> + VMSTATE_UINT32(src_reg, Exynos4210ClockState),
>> + VMSTATE_UINT32(div_reg, Exynos4210ClockState),
>> + VMSTATE_UINT8(mux_shift, Exynos4210ClockState),
>> + VMSTATE_UINT8(div_shift, Exynos4210ClockState),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +static const VMStateDescription vmstate_exynos4210_cmu = {
>> + .name = TYPE_EXYNOS4210_CMU,
>> + .version_id = 1,
>> + .minimum_version_id = 1,
>> + .minimum_version_id_old = 1,
>> + .fields = (VMStateField[]) {
>> + VMSTATE_UINT32_ARRAY(reg, Exynos4210CmuState,
>> + EXYNOS4210_CMU_REGS_MEM_SIZE / sizeof(uint32_t)),
>> + VMSTATE_STRUCT_VARRAY_INT32(clock, Exynos4210CmuState,
>> + clock_number, 0,
>> + vmstate_exynos4210_clock,
>> + Exynos4210ClockState),
>> + VMSTATE_END_OF_LIST()
>> + }
>> +};
>> +
>> +DeviceState *exynos4210_cmu_create(target_phys_addr_t addr,
>> + Exynos4210Cmu cmu_id)
>> +{
>> + DeviceState *dev;
>> + SysBusDevice *bus;
>> +
>> + dev = qdev_create(NULL, TYPE_EXYNOS4210_CMU);
>> +
>> + qdev_prop_set_int32(dev, "cmu_id", cmu_id);
>> +
>> + bus = sysbus_from_qdev(dev);
>> + qdev_init_nofail(dev);
>> + if (addr != (target_phys_addr_t)-1) {
>> + sysbus_mmio_map(bus, 0, addr);
>> + }
>> +
>> + return dev;
>> +}
>> +
>> +static int exynos4210_cmu_init(SysBusDevice *dev)
>> +{
>> + Exynos4210CmuState *s = FROM_SYSBUS(Exynos4210CmuState, dev);
>> + int i, n;
>> +
>> + memory_region_init_io(&s->iomem,&exynos4210_cmu_ops, s,
>> + TYPE_EXYNOS4210_CMU, EXYNOS4210_CMU_REGS_MEM_SIZE);
>> + sysbus_init_mmio(dev,&s->iomem);
>> +
>> + switch (s->cmu_id) {
>> + case EXYNOS4210_CMU_LEFTBUS:
>> + s->regs = exynos4210_cmu_leftbus_regs;
>> + s->regs_number = ARRAY_SIZE(exynos4210_cmu_leftbus_regs);
>> + break;
>> + case EXYNOS4210_CMU_RIGHTBUS:
>> + s->regs = exynos4210_cmu_rightbus_regs;
>> + s->regs_number = ARRAY_SIZE(exynos4210_cmu_rightbus_regs);
>> + break;
>> + case EXYNOS4210_CMU_TOP:
>> + s->regs = exynos4210_cmu_top_regs;
>> + s->regs_number = ARRAY_SIZE(exynos4210_cmu_top_regs);
>> + break;
>> + case EXYNOS4210_CMU_DMC:
>> + s->regs = exynos4210_cmu_dmc_regs;
>> + s->regs_number = ARRAY_SIZE(exynos4210_cmu_dmc_regs);
>> + break;
>> + case EXYNOS4210_CMU_CPU:
>> + s->regs = exynos4210_cmu_cpu_regs;
>> + s->regs_number = ARRAY_SIZE(exynos4210_cmu_cpu_regs);
>> + break;
>> + default:
>> + hw_error("Wrong CMU: %d\n", s->cmu_id);
>> + }
>> +
>> + for (i = 1, n = 0; i< EXYNOS4210_CLOCKS_NUMBER; i++) {
>> + if (s->cmu_id == exynos4210_clock[i]->cmu_id) {
>> + n++;
>> + }
>> + }
>> +
>> + s->clock =
>> + (Exynos4210ClockState *)g_malloc0(n * sizeof(Exynos4210ClockState));
>> +
>> + for (i = 1, s->clock_number = 0; i< EXYNOS4210_CLOCKS_NUMBER; i++) {
>> +
>> + if (s->cmu_id == exynos4210_clock[i]->cmu_id) {
>> +
>> + memcpy(&s->clock[s->clock_number], exynos4210_clock[i],
>> + sizeof(Exynos4210ClockState));
>> +
>> + QTAILQ_INIT(&s->clock[s->clock_number].clock_change_handler);
>> +
>> + PRINT_DEBUG("Clock %s was added to \"%s\"\n",
>> + s->clock[s->clock_number].name,
>> + exynos4210_cmu_path[s->cmu_id]);
>> +
>> + s->clock_number++;
>> + }
>> + }
>> +
>> + object_property_add_child(object_get_root(), exynos4210_cmu_path[s->cmu_id],
>> + OBJECT(dev), NULL);
>> +
>> + return 0;
>> +}
>> +
>> +static Property exynos4210_cmu_properties[] = {
>> + DEFINE_PROP_INT32("cmu_id", Exynos4210CmuState, cmu_id, UNSPECIFIED_CMU),
>> + DEFINE_PROP_END_OF_LIST(),
>> +};
>> +
>> +static void exynos4210_cmu_class_init(ObjectClass *klass, void *data)
>> +{
>> + DeviceClass *dc = DEVICE_CLASS(klass);
>> + SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
>> +
>> + k->init = exynos4210_cmu_init;
>> + dc->reset = exynos4210_cmu_reset;
>> + dc->props = exynos4210_cmu_properties;
>> + dc->vmsd =&vmstate_exynos4210_cmu;
>> +}
>> +
>> +static const TypeInfo exynos4210_cmu_info = {
>> + .name = TYPE_EXYNOS4210_CMU,
>> + .parent = TYPE_SYS_BUS_DEVICE,
>> + .instance_size = sizeof(Exynos4210CmuState),
>> + .class_init = exynos4210_cmu_class_init,
>> +};
>> +
>> +static void exynos4210_cmu_register_types(void)
>> +{
>> + type_register_static(&exynos4210_cmu_info);
>> +}
>> +
>> +type_init(exynos4210_cmu_register_types)
>> --
>> 1.7.5.4
>>
>>
^ permalink raw reply [flat|nested] only message in thread