From mboxrd@z Thu Jan 1 00:00:00 1970 Received: from eggs.gnu.org ([208.118.235.92]:44583) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Sm7ef-0004d3-Qr for qemu-devel@nongnu.org; Tue, 03 Jul 2012 14:16:58 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1Sm7ea-00077p-E4 for qemu-devel@nongnu.org; Tue, 03 Jul 2012 14:16:53 -0400 Received: from mailout4.w1.samsung.com ([210.118.77.14]:48729) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1Sm7eZ-00076x-Lj for qemu-devel@nongnu.org; Tue, 03 Jul 2012 14:16:48 -0400 Received: from eusync4.samsung.com (mailout4.w1.samsung.com [210.118.77.14]) by mailout4.w1.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTP id <0M6L002QTK4ZP020@mailout4.w1.samsung.com> for qemu-devel@nongnu.org; Tue, 03 Jul 2012 19:17:23 +0100 (BST) Received: from [106.109.9.187] by eusync4.samsung.com (Oracle Communications Messaging Server 7u4-24.01(7.0.4.24.0) 64bit (built Nov 17 2011)) with ESMTPA id <0M6L007FMK3TRP30@eusync4.samsung.com> for qemu-devel@nongnu.org; Tue, 03 Jul 2012 19:16:42 +0100 (BST) Date: Tue, 03 Jul 2012 22:16:38 +0400 From: Maksim Kozlov In-reply-to: <1341249195-28088-2-git-send-email-m.kozlov@samsung.com> Message-id: <4FF33706.6050007@samsung.com> MIME-version: 1.0 Content-type: text/plain; charset=UTF-8; format=flowed Content-transfer-encoding: QUOTED-PRINTABLE References: <1341249195-28088-1-git-send-email-m.kozlov@samsung.com> <1341249195-28088-2-git-send-email-m.kozlov@samsung.com> Subject: Re: [Qemu-devel] [PATCH v2 1/2] ARM: exynos4210: CMU support List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: peter.maydell@linaro.org, kyungmin.park@samsung.com, qemu-devel@nongnu.org 02.07.2012 21:13, Maksim Kozlov =D0=BF=D0=B8=D1=88=D0=B5=D1=82: > Add exynos4210 Clock Management Units emulation > > Signed-off-by: Maksim Kozlov > --- > hw/arm/Makefile.objs | 1 + > hw/exynos4210.c | 16 + > hw/exynos4210.h | 42 ++ > hw/exynos4210_cmu.c | 1464 +++++++++++++++++++++++++++++++++++++= +++++++++++++ > 4 files changed, 1523 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 +=3D realview_gic.o realview.o arm_sysctl.o= arm11mpcore.o a9mpcore.o > obj-y +=3D exynos4210_gic.o exynos4210_combiner.o exynos4210.o > obj-y +=3D exynos4_boards.o exynos4210_uart.o exynos4210_pwm.o > obj-y +=3D exynos4210_pmu.o exynos4210_mct.o exynos4210_fimd.o > +obj-y +=3D exynos4210_cmu.o > obj-y +=3D arm_l2x0.o > obj-y +=3D arm_mptimer.o a15mpcore.o > obj-y +=3D armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_e= net.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_AD= DR, NULL); > > + /* CMUs */ > + exynos4210_cmu_create(EXYNOS4210_CMU_LEFTBUS_BASE_ADDR, > + EXYNOS4210_= CMU_LEFTBUS); > + exynos4210_cmu_create(EXYNOS4210_CMU_RIGHTBUS_BASE_ADDR, > + EXYNOS4210_C= MU_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_A= DDR, > 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(Exynos4210= Irq *irqs, DeviceState *dev, > int ext); > > /* > + * Interface for exynos4210 Clock Management Units (CMUs) > + */ > +typedef enum { > + UNSPECIFIED_CMU =3D -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, Exynos= 4210Cmu 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..792a90b > --- /dev/null > +++ b/hw/exynos4210_cmu.c > @@ -0,0 +1,1464 @@ > +/* > + * exynos4210 Clock Management Units (CMUs) Emulation > + * > + * Copyright (C) 2011 Samsung Electronics Co Ltd. > + * Maksim Kozlov, > + * > + * 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 MERCHANTABI= LITY or > + * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public L= icense > + * for more details. > + * > + * You should have received a copy of the GNU General Public Lice= nse along > + * with this program; if not, see. > + * > + */ > + > +#include "sysbus.h" > + > +#include "exynos4210.h" > + > + > +#define DEBUG_CMU 1 Ouch! I accidentally left the debug output. I'll prepare another patc= hset > +#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 onl= y */ > +#define CLK_DIV_STAT_(block) (CLK_DIV_STAT + block) > +#define CLKDIV2_STAT 0x680 /* described for CMU_TOP onl= y */ > +#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 onl= y */ > +#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 const Exynos4210CmuReg exynos4210_cmu_leftbus_regs[] =3D { > + /* 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 const Exynos4210CmuReg exynos4210_cmu_rightbus_regs[] =3D { > + /* 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 const Exynos4210CmuReg exynos4210_cmu_top_regs[] =3D { > + /* CMU_TOP registers */ > + { "EPLL_LOCK", PLL_LOCK_(EPLL), 0x0= 0000FFF }, > + { "VPLL_LOCK", PLL_LOCK_(VPLL), 0x0= 0000FFF }, > + { "EPLL_CON0", PLL_CON0_(EPLL), 0x0= 0300301 }, > + { "EPLL_CON1", PLL_CON1_(EPLL), 0x0= 0000000 }, > + { "VPLL_CON0", PLL_CON0_(VPLL), 0x0= 0240201 }, > + { "VPLL_CON1", PLL_CON1_(VPLL), 0x6= 6010464 }, > + { "CLK_SRC_TOP0", CLK_SRC_(TOP0_BLK), 0x0= 0000000 }, > + { "CLK_SRC_TOP1", CLK_SRC_(TOP1_BLK), 0x0= 0000000 }, > + { "CLK_SRC_CAM", CLK_SRC_(CAM_BLK), 0x1= 1111111 }, > + { "CLK_SRC_TV", CLK_SRC_(TV_BLK), 0x0= 0000000 }, > + { "CLK_SRC_MFC", CLK_SRC_(MFC_BLK), 0x0= 0000000 }, > + { "CLK_SRC_G3D", CLK_SRC_(G3D_BLK), 0x0= 0000000 }, > + { "CLK_SRC_IMAGE", CLK_SRC_(IMAGE_BLK), 0x0= 0000000 }, > + { "CLK_SRC_LCD0", CLK_SRC_(LCD0_BLK), 0x0= 0001111 }, > + { "CLK_SRC_LCD1", CLK_SRC_(LCD1_BLK), 0x0= 0001111 }, > + { "CLK_SRC_MAUDIO", CLK_SRC_(MAUDIO_BLK), 0x0= 0000005 }, > + { "CLK_SRC_FSYS", CLK_SRC_(FSYS_BLK), 0x0= 0011111 }, > + { "CLK_SRC_PERIL0", CLK_SRC_(PERIL0_BLK), 0x0= 0011111 }, > + { "CLK_SRC_PERIL1", CLK_SRC_(PERIL1_BLK), 0x0= 1110055 }, > + { "CLK_SRC_MASK_TOP", CLK_SRC_MASK_(TOP_BLK), 0x0= 0000001 }, > + { "CLK_SRC_MASK_CAM", CLK_SRC_MASK_(CAM_BLK), 0x1= 1111111 }, > + { "CLK_SRC_MASK_TV", CLK_SRC_MASK_(TV_BLK), 0x0= 0000111 }, > + { "CLK_SRC_MASK_LCD0", CLK_SRC_MASK_(LCD0_BLK), 0x0= 0001111 }, > + { "CLK_SRC_MASK_LCD1", CLK_SRC_MASK_(LCD1_BLK), 0x0= 0001111 }, > + { "CLK_SRC_MASK_MAUDIO", CLK_SRC_MASK_(MAUDIO_BLK), 0x0= 0000001 }, > + { "CLK_SRC_MASK_FSYS", CLK_SRC_MASK_(FSYS_BLK), 0x0= 1011111 }, > + { "CLK_SRC_MASK_PERIL0", CLK_SRC_MASK_(PERIL0_BLK), 0x0= 0011111 }, > + { "CLK_SRC_MASK_PERIL1", CLK_SRC_MASK_(PERIL1_BLK), 0x0= 1110111 }, > + { "CLK_MUX_STAT_TOP", CLK_MUX_STAT_(TOP_BLK), 0x1= 1111111 }, > + { "CLK_MUX_STAT_MFC", CLK_MUX_STAT_(MFC_BLK), 0x0= 0000111 }, > + { "CLK_MUX_STAT_G3D", CLK_MUX_STAT_(G3D_BLK), 0x0= 0000111 }, > + { "CLK_MUX_STAT_IMAGE", CLK_MUX_STAT_(IMAGE_BLK), 0x0= 0000111 }, > + { "CLK_DIV_TOP", CLK_DIV_(TOP_BLK), 0x0= 0000000 }, > + { "CLK_DIV_CAM", CLK_DIV_(CAM_BLK), 0x0= 0000000 }, > + { "CLK_DIV_TV", CLK_DIV_(TV_BLK), 0x0= 0000000 }, > + { "CLK_DIV_MFC", CLK_DIV_(MFC_BLK), 0x0= 0000000 }, > + { "CLK_DIV_G3D", CLK_DIV_(G3D_BLK), 0x0= 0000000 }, > + { "CLK_DIV_IMAGE", CLK_DIV_(IMAGE_BLK), 0x0= 0000000 }, > + { "CLK_DIV_LCD0", CLK_DIV_(LCD0_BLK), 0x0= 0700000 }, > + { "CLK_DIV_LCD1", CLK_DIV_(LCD1_BLK), 0x0= 0700000 }, > + { "CLK_DIV_MAUDIO", CLK_DIV_(MAUDIO_BLK), 0x0= 0000000 }, > + { "CLK_DIV_FSYS0", CLK_DIV_(FSYS0_BLK), 0x0= 0B00000 }, > + { "CLK_DIV_FSYS1", CLK_DIV_(FSYS1_BLK), 0x0= 0000000 }, > + { "CLK_DIV_FSYS2", CLK_DIV_(FSYS2_BLK), 0x0= 0000000 }, > + { "CLK_DIV_FSYS3", CLK_DIV_(FSYS3_BLK), 0x0= 0000000 }, > + { "CLK_DIV_PERIL0", CLK_DIV_(PERIL0_BLK), 0x0= 0000000 }, > + { "CLK_DIV_PERIL1", CLK_DIV_(PERIL1_BLK), 0x0= 0000000 }, > + { "CLK_DIV_PERIL2", CLK_DIV_(PERIL2_BLK), 0x0= 0000000 }, > + { "CLK_DIV_PERIL3", CLK_DIV_(PERIL3_BLK), 0x0= 0000000 }, > + { "CLK_DIV_PERIL4", CLK_DIV_(PERIL4_BLK), 0x0= 0000000 }, > + { "CLK_DIV_PERIL5", CLK_DIV_(PERIL5_BLK), 0x0= 0000000 }, > + { "CLKDIV2_RATIO", CLKDIV2_RATIO, 0x1= 1111111 }, > + { "CLK_DIV_STAT_TOP", CLK_DIV_STAT_(TOP_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_CAM", CLK_DIV_STAT_(CAM_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_TV", CLK_DIV_STAT_(TV_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_MFC", CLK_DIV_STAT_(MFC_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_G3D", CLK_DIV_STAT_(G3D_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_IMAGE", CLK_DIV_STAT_(IMAGE_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_LCD0", CLK_DIV_STAT_(LCD0_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_LCD1", CLK_DIV_STAT_(LCD1_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_MAUDIO", CLK_DIV_STAT_(MAUDIO_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_FSYS0", CLK_DIV_STAT_(FSYS0_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_FSYS1", CLK_DIV_STAT_(FSYS1_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_FSYS2", CLK_DIV_STAT_(FSYS2_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_FSYS3", CLK_DIV_STAT_(FSYS3_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_PERIL0", CLK_DIV_STAT_(PERIL0_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_PERIL1", CLK_DIV_STAT_(PERIL1_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_PERIL2", CLK_DIV_STAT_(PERIL2_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_PERIL3", CLK_DIV_STAT_(PERIL3_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_PERIL4", CLK_DIV_STAT_(PERIL4_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_PERIL5", CLK_DIV_STAT_(PERIL5_BLK), 0x0= 0000000 }, > + { "CLKDIV2_STAT", CLKDIV2_STAT, 0x0= 0000000 }, > + { "CLK_GATE_SCLK_CAM", CLK_GATE_SCLK_(CAM_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_CAM", CLK_GATE_IP_(CAM_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_TV", CLK_GATE_IP_(TV_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_MFC", CLK_GATE_IP_(MFC_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_G3D", CLK_GATE_IP_(G3D_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_IMAGE", CLK_GATE_IP_(IMAGE_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_LCD0", CLK_GATE_IP_(LCD0_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_LCD1", CLK_GATE_IP_(LCD1_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_FSYS", CLK_GATE_IP_(FSYS_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_GPS", CLK_GATE_IP_(GPS_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_PERIL", CLK_GATE_IP_(PERIL_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_IP_PERIR", CLK_GATE_IP_(PERIR_BLK), 0xF= FFFFFFF }, > + { "CLK_GATE_BLOCK", CLK_GATE_BLOCK, 0xF= FFFFFFF }, > + { "CLKOUT_CMU_TOP", CLKOUT_CMU, 0x0= 0010000 }, > + { "CLKOUT_CMU_TOP_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x0= 0000000 }, > +}; > + > +static const Exynos4210CmuReg exynos4210_cmu_dmc_regs[] =3D { > + /* CMU_DMC registers */ > + { "CLK_SRC_DMC", CLK_SRC_(DMC_BLK), 0x0= 0010000 }, > + { "CLK_SRC_MASK_DMC", CLK_SRC_MASK_(DMC_BLK), 0x0= 0010000 }, > + { "CLK_MUX_STAT_DMC", CLK_MUX_STAT_(DMC_BLK), 0x1= 1100110 }, > + { "CLK_DIV_DMC0", CLK_DIV_(DMC0_BLK), 0x0= 0000000 }, > + { "CLK_DIV_DMC1", CLK_DIV_(DMC1_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_DMC0", CLK_DIV_STAT_(DMC0_BLK), 0x0= 0000000 }, > + { "CLK_DIV_STAT_DMC1", CLK_DIV_STAT_(DMC1_BLK), 0x0= 0000000 }, > + { "CLK_GATE_IP_DMC", CLK_GATE_IP_(DMC_BLK), 0xF= FFFFFFF }, > + { "CLKOUT_CMU_DMC", CLKOUT_CMU, 0x0= 0010000 }, > + { "CLKOUT_CMU_DMC_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x0= 0000000 }, > + { "DCGIDX_MAP0", DCGIDX_MAP0, 0xF= FFFFFFF }, > + { "DCGIDX_MAP1", DCGIDX_MAP1, 0xF= FFFFFFF }, > + { "DCGIDX_MAP2", DCGIDX_MAP2, 0xF= FFFFFFF }, > + { "DCGPERF_MAP0", DCGPERF_MAP0, 0xF= FFFFFFF }, > + { "DCGPERF_MAP1", DCGPERF_MAP1, 0xF= FFFFFFF }, > + { "DVCIDX_MAP", DVCIDX_MAP, 0xF= FFFFFFF }, > + { "FREQ_CPU", FREQ_CPU, 0x0= 0000000 }, > + { "FREQ_DPM", FREQ_DPM, 0x0= 0000000 }, > + { "DVSEMCLK_EN", DVSEMCLK_EN, 0x0= 0000000 }, > + { "MAXPERF", MAXPERF, 0x0= 0000000 }, > +}; > + > +static const Exynos4210CmuReg exynos4210_cmu_cpu_regs[] =3D { > + /* CMU_CPU registers */ > + { "APLL_LOCK", PLL_LOCK_(APLL), 0x00= 000FFF }, > + { "MPLL_LOCK", PLL_LOCK_(MPLL), 0x00= 000FFF }, > + { "APLL_CON0", PLL_CON0_(APLL), 0x00= C80601 }, > + { "APLL_CON1", PLL_CON1_(APLL), 0x00= 00001C }, > + { "MPLL_CON0", PLL_CON0_(MPLL), 0x00= C80601 }, > + { "MPLL_CON1", PLL_CON1_(MPLL), 0x00= 00001C }, > + { "CLK_SRC_CPU", CLK_SRC_(CPU_BLK), 0x00= 000000 }, > + { "CLK_MUX_STAT_CPU", CLK_MUX_STAT_(CPU_BLK), 0x00= 110101 }, > + { "CLK_DIV_CPU0", CLK_DIV_(CPU0_BLK), 0x00= 000000 }, > + { "CLK_DIV_CPU1", CLK_DIV_(CPU1_BLK), 0x00= 000000 }, > + { "CLK_DIV_STAT_CPU0", CLK_DIV_STAT_(CPU0_BLK), 0x00= 000000 }, > + { "CLK_DIV_STAT_CPU1", CLK_DIV_STAT_(CPU1_BLK), 0x00= 000000 }, > + { "CLK_GATE_SCLK_CPU", CLK_GATE_SCLK_(CPU_BLK), 0xFF= FFFFFF }, > + { "CLK_GATE_IP_CPU", CLK_GATE_IP_(CPU_BLK), 0xFF= FFFFFF }, > + { "CLKOUT_CMU_CPU", CLKOUT_CMU, 0x00= 010000 }, > + { "CLKOUT_CMU_CPU_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00= 000000 }, > + { "ARMCLK_STOPCTRL", ARMCLK_STOPCTRL, 0x00= 000044 }, > + { "ATCLK_STOPCTRL", ATCLK_STOPCTRL, 0x00= 000044 }, > + { "PARITYFAIL_STATUS", PARITYFAIL_STATUS, 0x00= 000000 }, > + { "PARITYFAIL_CLEAR", PARITYFAIL_CLEAR, 0x00= 000000 }, > + { "PWR_CTRL", PWR_CTRL, 0x00= 000033 }, > + { "APLL_CON0_L8", APLL_CON0_L8, 0x00= C80601 }, > + { "APLL_CON0_L7", APLL_CON0_L7, 0x00= C80601 }, > + { "APLL_CON0_L6", APLL_CON0_L6, 0x00= C80601 }, > + { "APLL_CON0_L5", APLL_CON0_L5, 0x00= C80601 }, > + { "APLL_CON0_L4", APLL_CON0_L4, 0x00= C80601 }, > + { "APLL_CON0_L3", APLL_CON0_L3, 0x00= C80601 }, > + { "APLL_CON0_L2", APLL_CON0_L2, 0x00= C80601 }, > + { "APLL_CON0_L1", APLL_CON0_L1, 0x00= C80601 }, > + { "IEM_CONTROL", IEM_CONTROL, 0x00= 000000 }, > + { "APLL_CON1_L8", APLL_CON1_L8, 0x00= 000000 }, > + { "APLL_CON1_L7", APLL_CON1_L7, 0x00= 000000 }, > + { "APLL_CON1_L6", APLL_CON1_L6, 0x00= 000000 }, > + { "APLL_CON1_L5", APLL_CON1_L5, 0x00= 000000 }, > + { "APLL_CON1_L4", APLL_CON1_L4, 0x00= 000000 }, > + { "APLL_CON1_L3", APLL_CON1_L3, 0x00= 000000 }, > + { "APLL_CON1_L2", APLL_CON1_L2, 0x00= 000000 }, > + { "APLL_CON1_L1", APLL_CON1_L1, 0x00= 000000 }, > + { "CLKDIV_IEM_L8", CLKDIV_IEM_L8, 0x00= 000000 }, > + { "CLKDIV_IEM_L7", CLKDIV_IEM_L7, 0x00= 000000 }, > + { "CLKDIV_IEM_L6", CLKDIV_IEM_L6, 0x00= 000000 }, > + { "CLKDIV_IEM_L5", CLKDIV_IEM_L5, 0x00= 000000 }, > + { "CLKDIV_IEM_L4", CLKDIV_IEM_L4, 0x00= 000000 }, > + { "CLKDIV_IEM_L3", CLKDIV_IEM_L3, 0x00= 000000 }, > + { "CLKDIV_IEM_L2", CLKDIV_IEM_L2, 0x00= 000000 }, > + { "CLKDIV_IEM_L1", CLKDIV_IEM_L1, 0x00= 000000 }, > +}; > + > +#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 sourc= e */ > + > +/* > + * Offsets in CLK_SRC_CPU register > + * for control MUXMPLL and MUXAPLL > + * > + * 0 =3D FINPLL, 1 =3D 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_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__SEL value which is stored > + * in appropriate CLK_MUX_STAT_ register > + */ > + uint8_t mux_shift; > + > + /* > + * Shift for_RATIO value which is stored > + * in appropriate CLK_DIV_ 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 */ > + const Exynos4210CmuReg *regs; > + int regs_number; > + > + Exynos4210ClockState *clock; > + int clock_number; /* how many clocks are controlled by given C= MU */ > +} Exynos4210CmuState; > + > + > +/* Clocks from Clock Pads */ > +/* > + * Two following clocks aren't controlled by any CMUs. These stru= ctures 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 const Exynos4210ClockState xxti =3D { > + .name =3D "XXTI", > + .id =3D EXYNOS4210_XXTI, > + .rate =3D 24000000, > + .cmu_id =3D UNSPECIFIED_CMU, > +}; > + > +/* Main source. XOM_0 is 1 */ > +static const Exynos4210ClockState xusbxti =3D { > + .name =3D "XUSBXTI", > + .id =3D EXYNOS4210_XUSBXTI, > + .rate =3D 24000000, > + .cmu_id =3D UNSPECIFIED_CMU, > +}; > + > +/* PLLs */ > + > +static const Exynos4210ClockState mpll =3D { > + .name =3D "MPLL", > + .id =3D EXYNOS4210_MPLL, > + .src_id =3D (XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI)= , > + .div_reg =3D PLL_CON0_(MPLL), > + .cmu_id =3D EXYNOS4210_CMU_CPU, > +}; > + > +static const Exynos4210ClockState apll =3D { > + .name =3D "APLL", > + .id =3D EXYNOS4210_APLL, > + .src_id =3D (XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI)= , > + .div_reg =3D PLL_CON0_(APLL), > + .cmu_id =3D EXYNOS4210_CMU_CPU, > +}; > + > + > +/**/ > + > +static const Exynos4210ClockState sclk_hdmi24m =3D { > + .name =3D "SCLK_HDMI24M", > + .id =3D EXYNOS4210_SCLK_HDMI24M, > + .rate =3D 24000000, > + .cmu_id =3D UNSPECIFIED_CMU, > +}; > + > +static const Exynos4210ClockState sclk_usbphy0 =3D { > + .name =3D "SCLK_USBPHY0", > + .id =3D EXYNOS4210_SCLK_USBPHY0, > + .rate =3D 24000000, > + .cmu_id =3D UNSPECIFIED_CMU, > +}; > + > +static const Exynos4210ClockState sclk_usbphy1 =3D { > + .name =3D "SCLK_USBPHY1", > + .id =3D EXYNOS4210_SCLK_USBPHY1, > + .rate =3D 24000000, > + .cmu_id =3D UNSPECIFIED_CMU, > +}; > + > +static Exynos4210ClockState sclk_hdmiphy =3D { > + .name =3D "SCLK_HDMIPHY", > + .id =3D EXYNOS4210_SCLK_HDMIPHY, > + .rate =3D 24000000, > + .cmu_id =3D UNSPECIFIED_CMU, > +}; > + > +static const Exynos4210ClockState sclk_mpll =3D { > + .name =3D "SCLK_MPLL", > + .id =3D EXYNOS4210_SCLK_MPLL, > + .src_ids =3D {XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI, > + EXYNOS4210_MPLL}, > + .src_reg =3D CLK_SRC_(CPU_BLK), > + .mux_shift =3D MUX_MPLL_SEL_SHIFT, > + .cmu_id =3D EXYNOS4210_CMU_CPU, > +}; > + > +static const Exynos4210ClockState sclk_apll =3D { > + .name =3D "SCLK_APLL", > + .id =3D EXYNOS4210_SCLK_APLL, > + .src_ids =3D {XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI, > + EXYNOS4210_APLL}, > + .src_reg =3D CLK_SRC_(CPU_BLK), > + .div_reg =3D CLK_DIV_(CPU0_BLK), > + .mux_shift =3D MUX_APLL_SEL_SHIFT, > + .div_shift =3D APLL_RATIO_SHIFT, > + .cmu_id =3D EXYNOS4210_CMU_CPU, > +}; > + > +static const Exynos4210ClockState aclk_100 =3D { > + .name =3D "ACLK_100", > + .id =3D EXYNOS4210_ACLK_100, > + .src_ids =3D {EXYNOS4210_SCLK_MPLL, EXYNOS4210_SCLK_APLL}, > + .src_reg =3D CLK_SRC_(TOP0_BLK), > + .div_reg =3D CLK_DIV_(TOP_BLK), > + .mux_shift =3D MUX_ACLK_100_SEL_SHIFT, > + .div_shift =3D ACLK_100_RATIO_SHIFT, > + .cmu_id =3D EXYNOS4210_CMU_TOP, > +}; > + > +static const Exynos4210ClockState sclk_uart0 =3D { > + .name =3D "SCLK_UART0", > + .id =3D EXYNOS4210_SCLK_UART0, > + .src_ids =3D {EXYNOS4210_XXTI, > + EXYNOS4210_XUSBXTI, > + EXYNOS4210_SCLK_HDMI24M, > + EXYNOS4210_SCLK_USBPHY0, > + EXYNOS4210_SCLK_USBPHY1, > + EXYNOS4210_SCLK_HDMIPHY, > + EXYNOS4210_SCLK_MPLL}, > + .src_reg =3D CLK_SRC_(PERIL0_BLK), > + .div_reg =3D CLK_DIV_(PERIL0_BLK), > + .mux_shift =3D UART0_SEL_SHIFT, > + .div_shift =3D UART0_DIV_SHIFT, > + .cmu_id =3D EXYNOS4210_CMU_TOP, > +}; > + > +static const Exynos4210ClockState sclk_uart1 =3D { > + .name =3D "SCLK_UART1", > + .id =3D EXYNOS4210_SCLK_UART1, > + .src_ids =3D {EXYNOS4210_XXTI, > + EXYNOS4210_XUSBXTI, > + EXYNOS4210_SCLK_HDMI24M, > + EXYNOS4210_SCLK_USBPHY0, > + EXYNOS4210_SCLK_USBPHY1, > + EXYNOS4210_SCLK_HDMIPHY, > + EXYNOS4210_SCLK_MPLL}, > + .src_reg =3D CLK_SRC_(PERIL0_BLK), > + .div_reg =3D CLK_DIV_(PERIL0_BLK), > + .mux_shift =3D UART1_SEL_SHIFT, > + .div_shift =3D UART1_DIV_SHIFT, > + .cmu_id =3D EXYNOS4210_CMU_TOP, > +}; > + > +static const Exynos4210ClockState sclk_uart2 =3D { > + .name =3D "SCLK_UART2", > + .id =3D EXYNOS4210_SCLK_UART2, > + .src_ids =3D {EXYNOS4210_XXTI, > + EXYNOS4210_XUSBXTI, > + EXYNOS4210_SCLK_HDMI24M, > + EXYNOS4210_SCLK_USBPHY0, > + EXYNOS4210_SCLK_USBPHY1, > + EXYNOS4210_SCLK_HDMIPHY, > + EXYNOS4210_SCLK_MPLL}, > + .src_reg =3D CLK_SRC_(PERIL0_BLK), > + .div_reg =3D CLK_DIV_(PERIL0_BLK), > + .mux_shift =3D UART2_SEL_SHIFT, > + .div_shift =3D UART2_DIV_SHIFT, > + .cmu_id =3D EXYNOS4210_CMU_TOP, > +}; > + > +static const Exynos4210ClockState sclk_uart3 =3D { > + .name =3D "SCLK_UART3", > + .id =3D EXYNOS4210_SCLK_UART3, > + .src_ids =3D {EXYNOS4210_XXTI, > + EXYNOS4210_XUSBXTI, > + EXYNOS4210_SCLK_HDMI24M, > + EXYNOS4210_SCLK_USBPHY0, > + EXYNOS4210_SCLK_USBPHY1, > + EXYNOS4210_SCLK_HDMIPHY, > + EXYNOS4210_SCLK_MPLL}, > + .src_reg =3D CLK_SRC_(PERIL0_BLK), > + .div_reg =3D CLK_DIV_(PERIL0_BLK), > + .mux_shift =3D UART3_SEL_SHIFT, > + .div_shift =3D UART3_DIV_SHIFT, > + .cmu_id =3D EXYNOS4210_CMU_TOP, > +}; > + > +static const Exynos4210ClockState sclk_uart4 =3D { > + .name =3D "SCLK_UART4", > + .id =3D EXYNOS4210_SCLK_UART4, > + .src_ids =3D {EXYNOS4210_XXTI, > + EXYNOS4210_XUSBXTI, > + EXYNOS4210_SCLK_HDMI24M, > + EXYNOS4210_SCLK_USBPHY0, > + EXYNOS4210_SCLK_USBPHY1, > + EXYNOS4210_SCLK_HDMIPHY, > + EXYNOS4210_SCLK_MPLL}, > + .src_reg =3D CLK_SRC_(PERIL0_BLK), > + .div_reg =3D CLK_DIV_(PERIL0_BLK), > + .mux_shift =3D UART4_SEL_SHIFT, > + .div_shift =3D UART4_DIV_SHIFT, > + .cmu_id =3D EXYNOS4210_CMU_TOP, > +}; > + > +/* > + * This array must correspond to Exynos4210Clock enumerator > + * which is defined in exynos4210.h file > + * > + */ > +static const Exynos4210ClockState *exynos4210_clock[] =3D { > + 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 const char exynos4210_cmu_path[][13] =3D { > + "cmu_leftbus", > + "cmu_rightbus", > + "cmu_top", > + "cmu_dmc", > + "cmu_cpu", > +}; > + > +#if DEBUG_CMU_EXTEND > +/* The only meaning of life - debugging. This function should be o= nly used > + * inside PRINT_DEBUG_EXTEND macros > + */ > +static const char *exynos4210_cmu_regname(Exynos4210CmuState *s, > + target_phys_addr_t offs= et) > +{ > + int i; > + > + for (i =3D 0; i< s->regs_number; i++) { > + if (offset =3D=3D 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 =3D exynos4210_clock[clock_id]->cmu_id; > + > + if (cmu_id =3D=3D UNSPECIFIED_CMU) { > + for (i =3D 1; i< EXYNOS4210_CLOCKS_NUMBER; i++) { > + if (exynos4210_clock[i]->id =3D=3D clock_id) { > + > + PRINT_DEBUG("Clock %s [%p] in CMU %d have been fou= nd\n", > + exynos4210_clock[i]->name, > + exynos4210_clock[i], > + cmu_id); > + > + return (Exynos4210ClockState *)exynos4210_clock[i= ]; > + } > + } > + } > + > + cmu =3D object_resolve_path(exynos4210_cmu_path[cmu_id], NULL)= ; > + s =3D OBJECT_CHECK(Exynos4210CmuState, cmu, TYPE_EXYNOS4210_CM= U); > + > + for (i =3D 0; i< s->clock_number; i++) { > + if (s->clock[i].id =3D=3D 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, v= oid *opaque) > +{ > + ClockChangeEntry *cce =3D g_malloc0(sizeof(ClockChangeEntry)); > + Exynos4210ClockState *clock =3D exynos4210_clock_find(clock_id= ); > + > + if (clock =3D=3D NULL) { > + hw_error("We aren't be able to find clock %d\n", clock_id)= ; > + } else if (clock->cmu_id =3D=3D UNSPECIFIED_CMU) { > + > + PRINT_DEBUG("Clock %s never are changed. Handler won't be = set.", > + exynos4210_clock[clock_id]->name); > + > + return; > + } > + > + cce->func =3D func; > + cce->opaque =3D 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 =3D exynos4210_clock_find(clock_id= ); > + > + if (clock =3D=3D 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, Exynos4210ClockSt= ate *pll) > +{ > + Exynos4210CmuState *s =3D opaque; > + Exynos4210ClockState *source; > + target_phys_addr_t offset =3D pll->div_reg; > + ClockChangeEntry *cce; > + uint32_t pdiv, mdiv, sdiv, enable; > + > + source =3D exynos4210_clock_find(pll->src_id); > + > + if (source =3D=3D NULL) { > + hw_error("We haven't find source clock %d (requested for %= s)\n", > + pll->src_id, pll->name); > + } > + > + /* > + * FOUT =3D MDIV * FIN / (PDIV * 2^(SDIV-1)) > + */ > + > + enable =3D (s->reg[I_(offset)]& PLL_ENABLE_MASK)>> PLL_ENABL= E_SHIFT; > + mdiv =3D (s->reg[I_(offset)]& PLL_MDIV_MASK)>> PLL_MDIV_SH= IFT; > + pdiv =3D (s->reg[I_(offset)]& PLL_PDIV_MASK)>> PLL_PDIV_SH= IFT; > + sdiv =3D (s->reg[I_(offset)]& PLL_SDIV_MASK)>> PLL_SDIV_SH= IFT; > + > + if (source) { > + if (enable) { > + pll->rate =3D mdiv * source->rate / (pdiv * (1<< (sdi= v-1))); > + } else { > + pll->rate =3D 0; > + } > + } else { > + hw_error("%s: Source undefined for %s\n", __func__, pll->n= ame); > + } > + > + 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)] |=3D PLL_LOCKED_MASK; > +} > + > + > +static void exynos4210_cmu_set_rate(void *opaque, Exynos4210Clock = clock_id) > +{ > + Exynos4210CmuState *s =3D opaque; > + Exynos4210ClockState *clock =3D exynos4210_clock_find(clock_id= ); > + ClockChangeEntry *cce; > + > + if (clock =3D=3D NULL) { > + hw_error("We haven't find source clock %d ", clock_id); > + } > + > + if ((clock->id =3D=3D EXYNOS4210_MPLL) || (clock->id =3D=3D EX= YNOS4210_APLL)) { > + > + exynos4210_cmu_set_pll(s, clock); > + > + } else if ((clock->cmu_id !=3D UNSPECIFIED_CMU)) { > + > + Exynos4210ClockState *source; > + > + uint32_t src_index =3D I_(clock->src_reg); > + uint32_t div_index =3D I_(clock->div_reg); > + > + clock->src_id =3D clock->src_ids[(s->reg[src_index]>> > + clock->mux_s= hift)& 0xf]; > + > + source =3D exynos4210_clock_find(clock->src_id); > + if (source =3D=3D NULL) { > + hw_error("We haven't find source clock %d (requested f= or %s)\n", > + clock->src_id, clock->name); > + } > + > + clock->rate =3D muldiv64(source->rate, 1, > + ((((clock->div_reg ? s->reg[div_i= ndex] : 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_re= g), > + 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 =3D 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 =3D=3D 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 =3D=3D 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 =3D opaque; > + uint32_t group, block; > + > + group =3D offset& GROUP_MASK; > + block =3D 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 =3D s->reg[I_(offset)]; > + s->reg[I_(offset)] =3D val; > + val =3D (val& ~PLL_LOCKED_MASK) | (pre_val& PLL_LOCK= ED_MASK); > + s->reg[I_(offset)] =3D val; > + exynos4210_cmu_set_rate(s, EXYNOS4210_APLL); > + break; > + } > + case MPLL: > + { > + uint32_t pre_val =3D s->reg[I_(offset)]; > + s->reg[I_(offset)] =3D val; > + val =3D (val& ~PLL_LOCKED_MASK) | (pre_val& PLL_LOCK= ED_MASK); > + s->reg[I_(offset)] =3D val; > + exynos4210_cmu_set_rate(s, EXYNOS4210_MPLL); > + break; > + } > + } > + break; > + case CLK_SRC: > + switch (block) { > + case CPU_BLK: > + { > + uint32_t pre_val =3D s->reg[I_(offset)]; > + s->reg[I_(offset)] =3D val; > + > + if (val& MUX_APLL_SEL) { > + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =3D > + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(APL= L_SEL_MASK)) | > + (2<< APLL_SEL_SHIFT); > + > + if ((pre_val& MUX_APLL_SEL) !=3D > + (s->reg[I_(offset)]& MUX_APLL_SEL)) { > + exynos4210_cmu_set_rate(s, EXYNOS4210_APLL); > + } > + > + } else { > + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =3D > + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(APL= L_SEL_MASK)) | > + (1<< APLL_SEL_SHIFT); > + > + if ((pre_val& MUX_APLL_SEL) !=3D > + (s->reg[I_(offset)]& MUX_APLL_SEL)) { > + exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_= XUSBXTI : > + EXYN= OS4210_XXTI); > + } > + } > + > + > + if (val& MUX_MPLL_SEL) { > + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =3D > + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(MPL= L_SEL_MASK)) | > + (2<< MPLL_SEL_SHIFT); > + > + if ((pre_val& MUX_MPLL_SEL) !=3D > + (s->reg[I_(offset)]& MUX_MPLL_SEL)) { > + exynos4210_cmu_set_rate(s, EXYNOS4210_MPLL); > + } > + > + } else { > + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =3D > + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(MPL= L_SEL_MASK)) | > + (1<< MPLL_SEL_SHIFT); > + > + if ((pre_val& MUX_MPLL_SEL) !=3D > + (s->reg[I_(offset)]& MUX_MPLL_SEL)) { > + exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_= XUSBXTI : > + EXYN= OS4210_XXTI); > + } > + } > + > + if (val& MUX_CORE_SEL) { > + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =3D > + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(COR= E_SEL_MASK)) | > + (2<< CORE_SEL_SHIFT); > + > + if ((pre_val& MUX_CORE_SEL) !=3D > + (s->reg[I_(offset)]& MUX_CORE_SEL)) { > + exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPL= L); > + } > + > + } else { > + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =3D > + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(COR= E_SEL_MASK)) | > + (1<< CORE_SEL_SHIFT); > + > + if ((pre_val& MUX_CORE_SEL) !=3D > + (s->reg[I_(offset)]& MUX_CORE_SEL)) { > + exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_= XUSBXTI : > + EXYN= OS4210_XXTI); > + } > + } > + > + if (val& MUX_HPM_SEL) { > + exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPLL); > + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =3D > + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(HPM= _SEL_MASK)) | > + (2<< HPM_SEL_SHIFT); > + > + if ((pre_val& MUX_HPM_SEL) !=3D > + (s->reg[I_(offset)]& MU= X_HPM_SEL)) { > + exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPL= L); > + } > + > + } else { > + s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =3D > + (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))]& ~(HP= M_SEL_MASK)) | > + (1<< HPM_SEL_SHIFT); > + > + if ((pre_val& MUX_HPM_SEL) !=3D > + (s->reg[I_(offset)]& MU= X_HPM_SEL)) { > + exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_= XUSBXTI : > + EXYN= OS4210_XXTI); > + } > + } > + } > + break; > + case TOP0_BLK: > + s->reg[I_(offset)] =3D val; > + exynos4210_cmu_set_rate(s, EXYNOS4210_ACLK_100); > + break; > + default: > + PRINT_ERROR("Unknown functional block: 0x%x\n", (int)b= lock); > + } > + break; > + case CLK_SRC_MASK: > + break; > + case CLK_MUX_STAT: > + break; > + case CLK_DIV: > + switch (block) { > + case TOP_BLK: > + s->reg[I_(offset)] =3D val; > + exynos4210_cmu_set_rate(s, EXYNOS4210_ACLK_100); > + break; > + case CPU0_BLK: > + s->reg[I_(offset)] =3D 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 =3D { > + .read =3D exynos4210_cmu_read, > + .write =3D exynos4210_cmu_write, > + .endianness =3D DEVICE_NATIVE_ENDIAN, > +}; > + > +static void clock_rate_changed(void *opaque) > +{ > + Exynos4210ClockState *cs =3D (Exynos4210ClockState *)opaque; > + Object *cmu =3D object_resolve_path(exynos4210_cmu_path[cs->cm= u_id], NULL); > + Exynos4210CmuState *s =3D OBJECT_CHECK(Exynos4210CmuState, cmu= , > + TYPE_EXY= NOS4210_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 =3D OBJECT_CHECK(Exynos4210CmuState, OBJ= ECT(dev), > + TYPE_EXY= NOS4210_CMU); > + int i, j; > + uint32_t index =3D 0; > + > + for (i =3D 0; i< s->regs_number; i++) { > + index =3D (s->regs[i].offset) / sizeof(uint32_t); > + s->reg[index] =3D s->regs[i].reset_value; > + } > + > + for (i =3D 0; i< s->clock_number; i++) { > + > + for (j =3D 0; j< SOURCES_NUMBER; j++) { > + > + if (s->clock[i].src_ids[j] =3D=3D UNSPECIFIED_CLOCK) { > + > + if (j =3D=3D 0) { > + /* > + * we have empty '.sources[]' array > + */ > + if (s->clock[i].src_id !=3D UNSPECIFIED_CLOCK)= { > + > + s->clock[i].src_ids[j] =3D s->clock[i].src= _id; > + > + } else { > + > + if (s->clock[i].cmu_id !=3D UNSPECIFIED_CM= U) { > + /* > + * We haven't any defined sources for = this clock. > + * Error during definition of appropri= ate 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 sour= ces */ > + } > + } /* src_ids[j] =3D=3D UNSPECIFIED_CLOCK */ > + > + Exynos4210ClockState *source =3D > + exynos4210_clock_find(s->clock[i]= .src_ids[j]); > + > + if (source =3D=3D 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 !=3D UNSPECIFIED_CMU) { > + > + exynos4210_register_clock_handler(clock_rate_chang= ed, > + 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 =3D { > + .name =3D TYPE_EXYNOS4210_CLOCK, > + .version_id =3D 1, > + .minimum_version_id =3D 1, > + .minimum_version_id_old =3D 1, > + .fields =3D (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 =3D { > + .name =3D TYPE_EXYNOS4210_CMU, > + .version_id =3D 1, > + .minimum_version_id =3D 1, > + .minimum_version_id_old =3D 1, > + .fields =3D (VMStateField[]) { > + VMSTATE_UINT32_ARRAY(reg, Exynos4210CmuState, > + EXYNOS4210_CMU_REGS_MEM_SIZE / sizeo= f(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, > + Exynos42= 10Cmu cmu_id) > +{ > + DeviceState *dev; > + SysBusDevice *bus; > + > + dev =3D qdev_create(NULL, TYPE_EXYNOS4210_CMU); > + > + qdev_prop_set_int32(dev, "cmu_id", cmu_id); > + > + bus =3D sysbus_from_qdev(dev); > + qdev_init_nofail(dev); > + if (addr !=3D (target_phys_addr_t)-1) { > + sysbus_mmio_map(bus, 0, addr); > + } > + > + return dev; > +} > + > +static int exynos4210_cmu_init(SysBusDevice *dev) > +{ > + Exynos4210CmuState *s =3D 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 =3D exynos4210_cmu_leftbus_regs; > + s->regs_number =3D ARRAY_SIZE(exynos4210_cmu_leftbus_regs)= ; > + break; > + case EXYNOS4210_CMU_RIGHTBUS: > + s->regs =3D exynos4210_cmu_rightbus_regs; > + s->regs_number =3D ARRAY_SIZE(exynos4210_cmu_rightbus_regs= ); > + break; > + case EXYNOS4210_CMU_TOP: > + s->regs =3D exynos4210_cmu_top_regs; > + s->regs_number =3D ARRAY_SIZE(exynos4210_cmu_top_regs); > + break; > + case EXYNOS4210_CMU_DMC: > + s->regs =3D exynos4210_cmu_dmc_regs; > + s->regs_number =3D ARRAY_SIZE(exynos4210_cmu_dmc_regs); > + break; > + case EXYNOS4210_CMU_CPU: > + s->regs =3D exynos4210_cmu_cpu_regs; > + s->regs_number =3D ARRAY_SIZE(exynos4210_cmu_cpu_regs); > + break; > + default: > + hw_error("Wrong CMU: %d\n", s->cmu_id); > + } > + > + for (i =3D 1, n =3D 0; i< EXYNOS4210_CLOCKS_NUMBER; i++) { > + if (s->cmu_id =3D=3D exynos4210_clock[i]->cmu_id) { > + n++; > + } > + } > + > + s->clock =3D > + (Exynos4210ClockState *)g_malloc0(n * sizeof(Exynos4210= ClockState)); > + > + for (i =3D 1, s->clock_number =3D 0; i< EXYNOS4210_CLOCKS_NUM= BER; i++) { > + > + if (s->cmu_id =3D=3D 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_ha= ndler); > + > + 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_pa= th[s->cmu_id], > + OBJECT(dev), NULL); > + > + return 0; > +} > + > +static Property exynos4210_cmu_properties[] =3D { > + DEFINE_PROP_INT32("cmu_id", Exynos4210CmuState, cmu_id, UNSPEC= IFIED_CMU), > + DEFINE_PROP_END_OF_LIST(), > +}; > + > +static void exynos4210_cmu_class_init(ObjectClass *klass, void *da= ta) > +{ > + DeviceClass *dc =3D DEVICE_CLASS(klass); > + SysBusDeviceClass *k =3D SYS_BUS_DEVICE_CLASS(klass); > + > + k->init =3D exynos4210_cmu_init; > + dc->reset =3D exynos4210_cmu_reset; > + dc->props =3D exynos4210_cmu_properties; > + dc->vmsd =3D&vmstate_exynos4210_cmu; > +} > + > +static const TypeInfo exynos4210_cmu_info =3D { > + .name =3D TYPE_EXYNOS4210_CMU, > + .parent =3D TYPE_SYS_BUS_DEVICE, > + .instance_size =3D sizeof(Exynos4210CmuState), > + .class_init =3D exynos4210_cmu_class_init, > +}; > + > +static void exynos4210_cmu_register_types(void) > +{ > + type_register_static(&exynos4210_cmu_info); > +} > + > +type_init(exynos4210_cmu_register_types)