qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH v3 02/14] ARM: exynos4210: CMU support


From: Peter Maydell
Subject: Re: [Qemu-devel] [PATCH v3 02/14] ARM: exynos4210: CMU support
Date: Mon, 12 Dec 2011 22:44:55 +0000

On 12 December 2011 06:43, Evgeny Voevodin <address@hidden> wrote:
> From: Maksim Kozlov <address@hidden>
>
> Add exynos4210 Clock Management Units emulation
>
> Signed-off-by: Evgeny Voevodin <address@hidden>
> ---
>  Makefile.target     |    2 +-
>  hw/exynos4210.c     |    7 +
>  hw/exynos4210.h     |   22 +
>  hw/exynos4210_cmu.c | 1146 
> +++++++++++++++++++++++++++++++++++++++++++++++++++
>  4 files changed, 1176 insertions(+), 1 deletions(-)
>  create mode 100644 hw/exynos4210_cmu.c
>
> diff --git a/Makefile.target b/Makefile.target
> index 624a142..ce4f1f8 100644
> --- a/Makefile.target
> +++ b/Makefile.target
> @@ -344,7 +344,7 @@ obj-arm-y = integratorcp.o versatilepb.o arm_pic.o 
> arm_timer.o
>  obj-arm-y += arm_boot.o pl011.o pl031.o pl050.o pl080.o pl110.o pl181.o 
> pl190.o
>  obj-arm-y += versatile_pci.o
>  obj-arm-y += realview_gic.o realview.o arm_sysctl.o arm11mpcore.o a9mpcore.o
> -obj-arm-y += exynos4210.o
> +obj-arm-y += exynos4210.o exynos4210_cmu.o
>  obj-arm-y += armv7m.o armv7m_nvic.o stellaris.o pl022.o stellaris_enet.o
>  obj-arm-y += pl061.o
>  obj-arm-y += arm-semi.o
> diff --git a/hw/exynos4210.c b/hw/exynos4210.c
> index 1550016..1a6e353 100644
> --- a/hw/exynos4210.c
> +++ b/hw/exynos4210.c
> @@ -60,6 +60,10 @@
>
>  #define EXYNOS4210_BASE_BOOT_ADDR           EXYNOS4210_DRAM0_BASE_ADDR
>
> +/* SFR Base Address for CMUs */
> +#define EXYNOS4210_CMU_BASE_ADDR            0x10030000
> +
> +
>  static struct arm_boot_info exynos4210_binfo = {
>         .loader_start     = EXYNOS4210_BASE_BOOT_ADDR,
>  };
> @@ -172,6 +176,9 @@ static void exynos4210_init(ram_addr_t ram_size,
>     memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
>             dram0_mem);
>
> +    /* CMU */
> +    sysbus_create_simple("exynos4210.cmu", EXYNOS4210_CMU_BASE_ADDR, NULL);
> +
>     /*** Load kernel ***/
>
>     exynos4210_binfo.ram_size = ram_size;
> diff --git a/hw/exynos4210.h b/hw/exynos4210.h
> index 7137630..683a4a6 100644
> --- a/hw/exynos4210.h
> +++ b/hw/exynos4210.h
> @@ -31,4 +31,26 @@
>
>  #define EXYNOS4210_MAX_CPUS                2
>
> +/*
> + * Interface for exynos4210 Clock Management Units (CMUs)
> + */
> +
> +typedef enum {
> +    XXTI,
> +    XUSBXTI,
> +    APLL,
> +    MPLL,
> +    SCLK_APLL,
> +    SCLK_MPLL,
> +    ACLK_100,
> +    SCLK_UART0,
> +    SCLK_UART1,
> +    SCLK_UART2,
> +    SCLK_UART3,
> +    SCLK_UART4,
> +    CLOCKS_NUMBER
> +} Exynos4210CmuClock;
> +
> +uint64_t exynos4210_cmu_get_rate(Exynos4210CmuClock clock);
> +
>  #endif /* EXYNOS4210_H_ */
> diff --git a/hw/exynos4210_cmu.c b/hw/exynos4210_cmu.c
> new file mode 100644
> index 0000000..fe4100c
> --- /dev/null
> +++ b/hw/exynos4210_cmu.c
> @@ -0,0 +1,1146 @@
> +/*
> + *  exynos4210 Clock Management Units (CMUs) Emulation
> + *
> + *  Copyright (C) 2011 Samsung Electronics Co Ltd.
> + *    Maksim Kozlov, <address@hidden>
> + *
> + *  Created on: 07.2011
> + *
> + *
> + *  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, write to the Free Software Foundation, Inc., 
> 51
> + *  Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
> + *
> + */
> +
> +#include "sysbus.h"
> +
> +#include "exynos4210.h"
> +
> +
> +
> +#undef DEBUG_CMU
> +
> +//#define DEBUG_CMU
> +//#define DEBUG_CMU_EXTEND
> +
> +
> +#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)
> +#define  PRINT_ERROR(fmt, args...) \
> +        do { \
> +            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
> +        } while (0)
> +
> +
> +#ifdef DEBUG_CMU
> +
> +    #undef PRINT_DEBUG
> +    #define  PRINT_DEBUG(fmt, args...)  \
> +        do { \
> +            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
> +        } while (0)
> +
> +    #undef PRINT_DEBUG_SIMPLE
> +    #define  PRINT_DEBUG_SIMPLE(fmt, args...)  \
> +        do { \
> +            fprintf(stderr, fmt, ## args); \
> +        } while (0)
> +
> +#ifdef DEBUG_CMU_EXTEND
> +
> +    #undef PRINT_DEBUG_EXTEND
> +    #define  PRINT_DEBUG_EXTEND(fmt, args...) \
> +        do { \
> +            fprintf(stderr, "  [%s:%d]   "fmt, __func__, __LINE__, ##args); \
> +        } while (0)
> +
> +#endif /* EXTEND */
> +#endif
> +
> +
> +/*
> + *  Offsets for CMUs registers
> + */
> +
> +/* CMU_LEFTBUS registers */
> +#define     CLK_SRC_LEFTBUS              0x04200
> +#define     CLK_MUX_STAT_LEFTBUS         0x04400
> +#define     CLK_DIV_LEFTBUS              0x04500
> +#define     CLK_DIV_STAT_LEFTBUS         0x04600
> +#define     CLK_GATE_IP_LEFTBUS          0x04800
> +#define     CLKOUT_CMU_LEFTBUS           0x04A00
> +#define     CLKOUT_CMU_LEFTBUS_DIV_STAT  0x04A04
> +/* CMU_RIGHTBUS registers */
> +#define     CLK_SRC_RIGHTBUS             0x08200
> +#define     CLK_MUX_STAT_RIGHTBUS        0x08400
> +#define     CLK_DIV_RIGHTBUS             0x08500
> +#define     CLK_DIV_STAT_RIGHTBUS        0x08600
> +#define     CLK_GATE_IP_RIGHTBUS         0x08800
> +#define     CLKOUT_CMU_RIGHTBUS          0x08A00
> +#define     CLKOUT_CMU_RIGHTBUS_DIV_STAT 0x08A04
> +/* CMU_TOP registers */
> +#define     EPLL_LOCK                    0x0C010
> +#define     VPLL_LOCK                    0x0C020
> +#define     EPLL_CON0                    0x0C110
> +#define     EPLL_CON1                    0x0C114
> +#define     VPLL_CON0                    0x0C120
> +#define     VPLL_CON1                    0x0C124
> +#define     CLK_SRC_TOP0                 0x0C210
> +#define     CLK_SRC_TOP1                 0x0C214
> +#define     CLK_SRC_CAM                  0x0C220
> +#define     CLK_SRC_TV                   0x0C224
> +#define     CLK_SRC_MFC                  0x0C228
> +#define     CLK_SRC_G3D                  0x0C22C
> +#define     CLK_SRC_IMAGE                0x0C230
> +#define     CLK_SRC_LCD0                 0x0C234
> +#define     CLK_SRC_LCD1                 0x0C238
> +#define     CLK_SRC_MAUDIO               0x0C23C
> +#define     CLK_SRC_FSYS                 0x0C240
> +#define     CLK_SRC_PERIL0               0x0C250
> +#define     CLK_SRC_PERIL1               0x0C254
> +#define     CLK_SRC_MASK_TOP             0x0C310
> +#define     CLK_SRC_MASK_CAM             0x0C320
> +#define     CLK_SRC_MASK_TV              0x0C324
> +#define     CLK_SRC_MASK_LCD0            0x0C334
> +#define     CLK_SRC_MASK_LCD1            0x0C338
> +#define     CLK_SRC_MASK_MAUDIO          0x0C33C
> +#define     CLK_SRC_MASK_FSYS            0x0C340
> +#define     CLK_SRC_MASK_PERIL0          0x0C350
> +#define     CLK_SRC_MASK_PERIL1          0x0C354
> +#define     CLK_MUX_STAT_TOP             0x0C410
> +#define     CLK_MUX_STAT_MFC             0x0C428
> +#define     CLK_MUX_STAT_G3D             0x0C42C
> +#define     CLK_MUX_STAT_IMAGE           0x0C430
> +#define     CLK_DIV_TOP                  0x0C510
> +#define     CLK_DIV_CAM                  0x0C520
> +#define     CLK_DIV_TV                   0x0C524
> +#define     CLK_DIV_MFC                  0x0C528
> +#define     CLK_DIV_G3D                  0x0C52C
> +#define     CLK_DIV_IMAGE                0x0C530
> +#define     CLK_DIV_LCD0                 0x0C534
> +#define     CLK_DIV_LCD1                 0x0C538
> +#define     CLK_DIV_MAUDIO               0x0C53C
> +#define     CLK_DIV_FSYS0                0x0C540
> +#define     CLK_DIV_FSYS1                0x0C544
> +#define     CLK_DIV_FSYS2                0x0C548
> +#define     CLK_DIV_FSYS3                0x0C54C
> +#define     CLK_DIV_PERIL0               0x0C550
> +#define     CLK_DIV_PERIL1               0x0C554
> +#define     CLK_DIV_PERIL2               0x0C558
> +#define     CLK_DIV_PERIL3               0x0C55C
> +#define     CLK_DIV_PERIL4               0x0C560
> +#define     CLK_DIV_PERIL5               0x0C564
> +#define     CLKDIV2_RATIO                0x0C580
> +#define     CLK_DIV_STAT_TOP             0x0C610
> +#define     CLK_DIV_STAT_CAM             0x0C620
> +#define     CLK_DIV_STAT_TV              0x0C624
> +#define     CLK_DIV_STAT_MFC             0x0C628
> +#define     CLK_DIV_STAT_G3D             0x0C62C
> +#define     CLK_DIV_STAT_IMAGE           0x0C630
> +#define     CLK_DIV_STAT_LCD0            0x0C634
> +#define     CLK_DIV_STAT_LCD1            0x0C638
> +#define     CLK_DIV_STAT_MAUDIO          0x0C63C
> +#define     CLK_DIV_STAT_FSYS0           0x0C640
> +#define     CLK_DIV_STAT_FSYS1           0x0C644
> +#define     CLK_DIV_STAT_FSYS2           0x0C648
> +#define     CLK_DIV_STAT_FSYS3           0x0C64C
> +#define     CLK_DIV_STAT_PERIL0          0x0C650
> +#define     CLK_DIV_STAT_PERIL1          0x0C654
> +#define     CLK_DIV_STAT_PERIL2          0x0C658
> +#define     CLK_DIV_STAT_PERIL3          0x0C65C
> +#define     CLK_DIV_STAT_PERIL4          0x0C660
> +#define     CLK_DIV_STAT_PERIL5          0x0C664
> +#define     CLKDIV2_STAT                 0x0C680
> +#define     CLK_GATE_SCLK_CAM            0x0C820
> +#define     CLK_GATE_IP_CAM              0x0C920
> +#define     CLK_GATE_IP_TV               0x0C924
> +#define     CLK_GATE_IP_MFC              0x0C928
> +#define     CLK_GATE_IP_G3D              0x0C92C
> +#define     CLK_GATE_IP_IMAGE            0x0C930
> +#define     CLK_GATE_IP_LCD0             0x0C934
> +#define     CLK_GATE_IP_LCD1             0x0C938
> +#define     CLK_GATE_IP_FSYS             0x0C940
> +#define     CLK_GATE_IP_GPS              0x0C94C
> +#define     CLK_GATE_IP_PERIL            0x0C950
> +#define     CLK_GATE_IP_PERIR            0x0C960
> +#define     CLK_GATE_BLOCK               0x0C970
> +#define     CLKOUT_CMU_TOP               0x0CA00
> +#define     CLKOUT_CMU_TOP_DIV_STAT      0x0CA04
> +/* CMU_DMC registers */
> +#define     CLK_SRC_DMC                  0x10200
> +#define     CLK_SRC_MASK_DMC             0x10300
> +#define     CLK_MUX_STAT_DMC             0x10400
> +#define     CLK_DIV_DMC0                 0x10500
> +#define     CLK_DIV_DMC1                 0x10504
> +#define     CLK_DIV_STAT_DMC0            0x10600
> +#define     CLK_DIV_STAT_DMC1            0x10604
> +#define     CLK_GATE_IP_DMC              0x10900
> +#define     CLKOUT_CMU_DMC               0x10A00
> +#define     CLKOUT_CMU_DMC_DIV_STAT      0x10A04
> +#define     DCGIDX_MAP0                  0x11000
> +#define     DCGIDX_MAP1                  0x11004
> +#define     DCGIDX_MAP2                  0x11008
> +#define     DCGPERF_MAP0                 0x11020
> +#define     DCGPERF_MAP1                 0x11024
> +#define     DVCIDX_MAP                   0x11040
> +#define     FREQ_CPU                     0x11060
> +#define     FREQ_DPM                     0x11064
> +#define     DVSEMCLK_EN                  0x11080
> +#define     MAXPERF                      0x11084
> +#define     APLL_LOCK                    0x14000
> +#define     MPLL_LOCK                    0x14008
> +#define     APLL_CON0                    0x14100
> +#define     APLL_CON1                    0x14104
> +#define     MPLL_CON0                    0x14108
> +#define     MPLL_CON1                    0x1410C
> +/* CMU_CPU registers */
> +#define     CLK_SRC_CPU                  0x14200
> +#define     CLK_MUX_STAT_CPU             0x14400
> +#define     CLK_DIV_CPU0                 0x14500
> +#define     CLK_DIV_CPU1                 0x14504
> +#define     CLK_DIV_STAT_CPU0            0x14600
> +#define     CLK_DIV_STAT_CPU1            0x14604
> +#define     CLK_GATE_SCLK_CPU            0x14800
> +#define     CLK_GATE_IP_CPU              0x14900
> +#define     CLKOUT_CMU_CPU               0x14A00
> +#define     CLKOUT_CMU_CPU_DIV_STAT      0x14A04
> +#define     ARMCLK_STOPCTRL              0x15000
> +#define     ATCLK_STOPCTRL               0x15004
> +#define     PARITYFAIL_STATUS            0x15010
> +#define     PARITYFAIL_CLEAR             0x15014
> +#define     PWR_CTRL                     0x15020
> +#define     APLL_CON0_L8                 0x15100
> +#define     APLL_CON0_L7                 0x15104
> +#define     APLL_CON0_L6                 0x15108
> +#define     APLL_CON0_L5                 0x1510C
> +#define     APLL_CON0_L4                 0x15110
> +#define     APLL_CON0_L3                 0x15114
> +#define     APLL_CON0_L2                 0x15118
> +#define     APLL_CON0_L1                 0x1511C
> +#define     IEM_CONTROL                  0x15120
> +#define     APLL_CON1_L8                 0x15200
> +#define     APLL_CON1_L7                 0x15204
> +#define     APLL_CON1_L6                 0x15208
> +#define     APLL_CON1_L5                 0x1520C
> +#define     APLL_CON1_L4                 0x15210
> +#define     APLL_CON1_L3                 0x15214
> +#define     APLL_CON1_L2                 0x15218
> +#define     APLL_CON1_L1                 0x1521C
> +#define     CLKDIV_IEM_L8                0x15300
> +#define     CLKDIV_IEM_L7                0x15304
> +#define     CLKDIV_IEM_L6                0x15308
> +#define     CLKDIV_IEM_L5                0x1530C
> +#define     CLKDIV_IEM_L4                0x15310
> +#define     CLKDIV_IEM_L3                0x15314
> +#define     CLKDIV_IEM_L2                0x15318
> +#define     CLKDIV_IEM_L1                0x1531C
> +
> +
> +typedef struct Exynos4210CmuReg {
> +        const char *name; /* for debugging */
> +        uint32_t    offset;
> +        uint32_t    reset_value;
> +} Exynos4210CmuReg;
> +
> +
> +static Exynos4210CmuReg exynos4210_cmu_regs[] = {
> +    /* CMU_LEFTBUS registers */
> +    {"CLK_SRC_LEFTBUS",              CLK_SRC_LEFTBUS,              
> 0x00000000},
> +    {"CLK_MUX_STAT_LEFTBUS",         CLK_MUX_STAT_LEFTBUS,         
> 0x00000001},
> +    {"CLK_DIV_LEFTBUS",              CLK_DIV_LEFTBUS,              
> 0x00000000},
> +    {"CLK_DIV_STAT_LEFTBUS",         CLK_DIV_STAT_LEFTBUS,         
> 0x00000000},
> +    {"CLK_GATE_IP_LEFTBUS",          CLK_GATE_IP_LEFTBUS,          
> 0xFFFFFFFF},
> +    {"CLKOUT_CMU_LEFTBUS",           CLKOUT_CMU_LEFTBUS,           
> 0x00010000},
> +    {"CLKOUT_CMU_LEFTBUS_DIV_STAT",  CLKOUT_CMU_LEFTBUS_DIV_STAT,  
> 0x00000000},
> +    /* CMU_RIGHTBUS registers */
> +    {"CLK_SRC_RIGHTBUS",             CLK_SRC_RIGHTBUS,             
> 0x00000000},
> +    {"CLK_MUX_STAT_RIGHTBUS",        CLK_MUX_STAT_RIGHTBUS,        
> 0x00000001},
> +    {"CLK_DIV_RIGHTBUS",             CLK_DIV_RIGHTBUS,             
> 0x00000000},
> +    {"CLK_DIV_STAT_RIGHTBUS",        CLK_DIV_STAT_RIGHTBUS,        
> 0x00000000},
> +    {"CLK_GATE_IP_RIGHTBUS",         CLK_GATE_IP_RIGHTBUS,         
> 0xFFFFFFFF},
> +    {"CLKOUT_CMU_RIGHTBUS",          CLKOUT_CMU_RIGHTBUS,          
> 0x00010000},
> +    {"CLKOUT_CMU_RIGHTBUS_DIV_STAT", CLKOUT_CMU_RIGHTBUS_DIV_STAT, 
> 0x00000000},
> +    /* CMU_TOP registers */
> +    {"EPLL_LOCK",               EPLL_LOCK,               0x00000FFF},
> +    {"VPLL_LOCK",               VPLL_LOCK,               0x00000FFF},
> +    {"EPLL_CON0",               EPLL_CON0,               0x00300301},
> +    {"EPLL_CON1",               EPLL_CON1,               0x00000000},
> +    {"VPLL_CON0",               VPLL_CON0,               0x00240201},
> +    {"VPLL_CON1",               VPLL_CON1,               0x66010464},
> +    {"CLK_SRC_TOP0",            CLK_SRC_TOP0,            0x00000000},
> +    {"CLK_SRC_TOP1",            CLK_SRC_TOP1,            0x00000000},
> +    {"CLK_SRC_CAM",             CLK_SRC_CAM,             0x11111111},
> +    {"CLK_SRC_TV",              CLK_SRC_TV,              0x00000000},
> +    {"CLK_SRC_MFC",             CLK_SRC_MFC,             0x00000000},
> +    {"CLK_SRC_G3D",             CLK_SRC_G3D,             0x00000000},
> +    {"CLK_SRC_IMAGE",           CLK_SRC_IMAGE,           0x00000000},
> +    {"CLK_SRC_LCD0",            CLK_SRC_LCD0,            0x00001111},
> +    {"CLK_SRC_LCD1",            CLK_SRC_LCD1,            0x00001111},
> +    {"CLK_SRC_MAUDIO",          CLK_SRC_MAUDIO,          0x00000005},
> +    {"CLK_SRC_FSYS",            CLK_SRC_FSYS,            0x00011111},
> +    {"CLK_SRC_PERIL0",          CLK_SRC_PERIL0,          0x00011111},
> +    {"CLK_SRC_PERIL1",          CLK_SRC_PERIL1,          0x01110055},
> +    {"CLK_SRC_MASK_TOP",        CLK_SRC_MASK_TOP,        0x00000001},
> +    {"CLK_SRC_MASK_CAM",        CLK_SRC_MASK_CAM,        0x11111111},
> +    {"CLK_SRC_MASK_TV",         CLK_SRC_MASK_TV,         0x00000111},
> +    {"CLK_SRC_MASK_LCD0",       CLK_SRC_MASK_LCD0,       0x00001111},
> +    {"CLK_SRC_MASK_LCD1",       CLK_SRC_MASK_LCD1,       0x00001111},
> +    {"CLK_SRC_MASK_MAUDIO",     CLK_SRC_MASK_MAUDIO,     0x00000001},
> +    {"CLK_SRC_MASK_FSYS",       CLK_SRC_MASK_FSYS,       0x01011111},
> +    {"CLK_SRC_MASK_PERIL0",     CLK_SRC_MASK_PERIL0,     0x00011111},
> +    {"CLK_SRC_MASK_PERIL1",     CLK_SRC_MASK_PERIL1,     0x01110111},
> +    {"CLK_MUX_STAT_TOP",        CLK_MUX_STAT_TOP,        0x11111111},
> +    {"CLK_MUX_STAT_MFC",        CLK_MUX_STAT_MFC,        0x00000111},
> +    {"CLK_MUX_STAT_G3D",        CLK_MUX_STAT_G3D,        0x00000111},
> +    {"CLK_MUX_STAT_IMAGE",      CLK_MUX_STAT_IMAGE,      0x00000111},
> +    {"CLK_DIV_TOP",             CLK_DIV_TOP,             0x00000000},
> +    {"CLK_DIV_CAM",             CLK_DIV_CAM,             0x00000000},
> +    {"CLK_DIV_TV",              CLK_DIV_TV,              0x00000000},
> +    {"CLK_DIV_MFC",             CLK_DIV_MFC,             0x00000000},
> +    {"CLK_DIV_G3D",             CLK_DIV_G3D,             0x00000000},
> +    {"CLK_DIV_IMAGE",           CLK_DIV_IMAGE,           0x00000000},
> +    {"CLK_DIV_LCD0",            CLK_DIV_LCD0,            0x00700000},
> +    {"CLK_DIV_LCD1",            CLK_DIV_LCD1,            0x00700000},
> +    {"CLK_DIV_MAUDIO",          CLK_DIV_MAUDIO,          0x00000000},
> +    {"CLK_DIV_FSYS0",           CLK_DIV_FSYS0,           0x00B00000},
> +    {"CLK_DIV_FSYS1",           CLK_DIV_FSYS1,           0x00000000},
> +    {"CLK_DIV_FSYS2",           CLK_DIV_FSYS2,           0x00000000},
> +    {"CLK_DIV_FSYS3",           CLK_DIV_FSYS3,           0x00000000},
> +    {"CLK_DIV_PERIL0",          CLK_DIV_PERIL0,          0x00000000},
> +    {"CLK_DIV_PERIL1",          CLK_DIV_PERIL1,          0x00000000},
> +    {"CLK_DIV_PERIL2",          CLK_DIV_PERIL2,          0x00000000},
> +    {"CLK_DIV_PERIL3",          CLK_DIV_PERIL3,          0x00000000},
> +    {"CLK_DIV_PERIL4",          CLK_DIV_PERIL4,          0x00000000},
> +    {"CLK_DIV_PERIL5",          CLK_DIV_PERIL5,          0x00000000},
> +    {"CLKDIV2_RATIO",           CLKDIV2_RATIO,           0x11111111},
> +    {"CLK_DIV_STAT_TOP",        CLK_DIV_STAT_TOP,        0x00000000},
> +    {"CLK_DIV_STAT_CAM",        CLK_DIV_STAT_CAM,        0x00000000},
> +    {"CLK_DIV_STAT_TV",         CLK_DIV_STAT_TV,         0x00000000},
> +    {"CLK_DIV_STAT_MFC",        CLK_DIV_STAT_MFC,        0x00000000},
> +    {"CLK_DIV_STAT_G3D",        CLK_DIV_STAT_G3D,        0x00000000},
> +    {"CLK_DIV_STAT_IMAGE",      CLK_DIV_STAT_IMAGE,      0x00000000},
> +    {"CLK_DIV_STAT_LCD0",       CLK_DIV_STAT_LCD0,       0x00000000},
> +    {"CLK_DIV_STAT_LCD1",       CLK_DIV_STAT_LCD1,       0x00000000},
> +    {"CLK_DIV_STAT_MAUDIO",     CLK_DIV_STAT_MAUDIO,     0x00000000},
> +    {"CLK_DIV_STAT_FSYS0",      CLK_DIV_STAT_FSYS0,      0x00000000},
> +    {"CLK_DIV_STAT_FSYS1",      CLK_DIV_STAT_FSYS1,      0x00000000},
> +    {"CLK_DIV_STAT_FSYS2",      CLK_DIV_STAT_FSYS2,      0x00000000},
> +    {"CLK_DIV_STAT_FSYS3",      CLK_DIV_STAT_FSYS3,      0x00000000},
> +    {"CLK_DIV_STAT_PERIL0",     CLK_DIV_STAT_PERIL0,     0x00000000},
> +    {"CLK_DIV_STAT_PERIL1",     CLK_DIV_STAT_PERIL1,     0x00000000},
> +    {"CLK_DIV_STAT_PERIL2",     CLK_DIV_STAT_PERIL2,     0x00000000},
> +    {"CLK_DIV_STAT_PERIL3",     CLK_DIV_STAT_PERIL3,     0x00000000},
> +    {"CLK_DIV_STAT_PERIL4",     CLK_DIV_STAT_PERIL4,     0x00000000},
> +    {"CLK_DIV_STAT_PERIL5",     CLK_DIV_STAT_PERIL5,     0x00000000},
> +    {"CLKDIV2_STAT",            CLKDIV2_STAT,            0x00000000},
> +    {"CLK_GATE_SCLK_CAM",       CLK_GATE_SCLK_CAM,       0xFFFFFFFF},
> +    {"CLK_GATE_IP_CAM",         CLK_GATE_IP_CAM,         0xFFFFFFFF},
> +    {"CLK_GATE_IP_TV",          CLK_GATE_IP_TV,          0xFFFFFFFF},
> +    {"CLK_GATE_IP_MFC",         CLK_GATE_IP_MFC,         0xFFFFFFFF},
> +    {"CLK_GATE_IP_G3D",         CLK_GATE_IP_G3D,         0xFFFFFFFF},
> +    {"CLK_GATE_IP_IMAGE",       CLK_GATE_IP_IMAGE,       0xFFFFFFFF},
> +    {"CLK_GATE_IP_LCD0",        CLK_GATE_IP_LCD0,        0xFFFFFFFF},
> +    {"CLK_GATE_IP_LCD1",        CLK_GATE_IP_LCD1,        0xFFFFFFFF},
> +    {"CLK_GATE_IP_FSYS",        CLK_GATE_IP_FSYS,        0xFFFFFFFF},
> +    {"CLK_GATE_IP_GPS",         CLK_GATE_IP_GPS,         0xFFFFFFFF},
> +    {"CLK_GATE_IP_PERIL",       CLK_GATE_IP_PERIL,       0xFFFFFFFF},
> +    {"CLK_GATE_IP_PERIR",       CLK_GATE_IP_PERIR,       0xFFFFFFFF},
> +    {"CLK_GATE_BLOCK",          CLK_GATE_BLOCK,          0xFFFFFFFF},
> +    {"CLKOUT_CMU_TOP",          CLKOUT_CMU_TOP,          0x00010000},
> +    {"CLKOUT_CMU_TOP_DIV_STAT", CLKOUT_CMU_TOP_DIV_STAT, 0x00000000},
> +    /* CMU_DMC registers */
> +    {"CLK_SRC_DMC",             CLK_SRC_DMC,             0x00010000},
> +    {"CLK_SRC_MASK_DMC",        CLK_SRC_MASK_DMC,        0x00010000},
> +    {"CLK_MUX_STAT_DMC",        CLK_MUX_STAT_DMC,        0x11100110},
> +    {"CLK_DIV_DMC0",            CLK_DIV_DMC0,            0x00000000},
> +    {"CLK_DIV_DMC1",            CLK_DIV_DMC1,            0x00000000},
> +    {"CLK_DIV_STAT_DMC0",       CLK_DIV_STAT_DMC0,       0x00000000},
> +    {"CLK_DIV_STAT_DMC1",       CLK_DIV_STAT_DMC1,       0x00000000},
> +    {"CLK_GATE_IP_DMC",         CLK_GATE_IP_DMC,         0xFFFFFFFF},
> +    {"CLKOUT_CMU_DMC",          CLKOUT_CMU_DMC,          0x00010000},
> +    {"CLKOUT_CMU_DMC_DIV_STAT", CLKOUT_CMU_DMC_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},
> +    {"APLL_LOCK",               APLL_LOCK,               0x00000FFF},
> +    {"MPLL_LOCK",               MPLL_LOCK,               0x00000FFF},
> +    {"APLL_CON0",               APLL_CON0,               0x00C80601},
> +    {"APLL_CON1",               APLL_CON1,               0x0000001C},
> +    {"MPLL_CON0",               MPLL_CON0,               0x00C80601},
> +    {"MPLL_CON1",               MPLL_CON1,               0x0000001C},
> +    /* CMU_CPU registers */
> +    {"CLK_SRC_CPU",             CLK_SRC_CPU,             0x00000000},
> +    {"CLK_MUX_STAT_CPU",        CLK_MUX_STAT_CPU,        0x00110101},
> +    {"CLK_DIV_CPU0",            CLK_DIV_CPU0,            0x00000000},
> +    {"CLK_DIV_CPU1",            CLK_DIV_CPU1,            0x00000000},
> +    {"CLK_DIV_STAT_CPU0",       CLK_DIV_STAT_CPU0,       0x00000000},
> +    {"CLK_DIV_STAT_CPU1",       CLK_DIV_STAT_CPU1,       0x00000000},
> +    {"CLK_GATE_SCLK_CPU",       CLK_GATE_SCLK_CPU,       0xFFFFFFFF},
> +    {"CLK_GATE_IP_CPU",         CLK_GATE_IP_CPU,         0xFFFFFFFF},
> +    {"CLKOUT_CMU_CPU",          CLKOUT_CMU_CPU,          0x00010000},
> +    {"CLKOUT_CMU_CPU_DIV_STAT", CLKOUT_CMU_CPU_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},
> +};
> +
> +
> +/*
> + * There are five CMUs:
> + *
> + *  CMU_LEFTBUS
> + *  CMU_RIGHTBUS
> + *  CMU_TOP
> + *  CMU_DMC
> + *  CMU_CPU
> + *
> + *  each of them uses 16KB address space for SFRs
> + *
> + *  + 0x4000 because SFR region for CMUs starts at 0x10030000,
> + *  but the first CMU (CMU_LEFTBUS) starts with this offset
> + *
> + */
> +#define EXYNOS4210_CMU_REGS_MEM_SIZE   (0x4000 * 5 + 0x4000)

It seems a bit unlikely to me that there's really a single indivisble
bit of hardware with 23 kilobytes worth of register area. Is there
a better way of structuring this so that there are a number of
sub-memory-regions that cover this space each with their own
read/write functions (and perhaps with their own state structs)?
(eg instantiate five CPUs at the right locations.)

> +
> +/*
> + * 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
> +
> +typedef struct {
> +        SysBusDevice busdev;
> +        MemoryRegion iomem;
> +
> +        uint32_t reg[EXYNOS4210_CMU_REGS_MEM_SIZE];
> +
> +} Exynos4210CmuState;
> +
> +#define SOURCES_NUMBER    9
> +#define RECIPIENTS_NUMBER 9
> +
> +typedef struct Exynos4210CmuClockState {
> +
> +        const char  *name;
> +        uint64_t     rate;
> +
> +        /* Current source clock */
> +        struct Exynos4210CmuClockState *source;
> +        /*
> +         * Available sources. Their order must correspond to CLK_SRC_ 
> register
> +         */
> +        struct Exynos4210CmuClockState *sources[SOURCES_NUMBER];
> +        /* Who uses this clock? */
> +        struct Exynos4210CmuClockState *recipients[RECIPIENTS_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;
> +
> +} Exynos4210CmuClockState;

So, how does this compare with the struct clk in hw/omap_clk.c ?
Is there a useful generalisation we can make rather than having
every SOC model doing its own thing for clock trees?

> +
> +/* Clocks from Clock Pads */
> +
> +/* It should be used only for testing purposes. XOM_0 is 0 */
> +static Exynos4210CmuClockState xxti = {
> +        .name       = "XXTI",
> +        .rate       = 24000000,
> +};
> +
> +/* Main source. XOM_0 is 1 */
> +static Exynos4210CmuClockState xusbxti = {
> +        .name       = "XUSBXTI",
> +        .rate       = 24000000,
> +};
> +
> +/* PLLs */
> +
> +static Exynos4210CmuClockState mpll = {
> +        .name       = "MPLL",
> +        .source     = (XOM_0 ? &xusbxti : &xxti),
> +};
> +
> +static Exynos4210CmuClockState apll = {
> +        .name       = "APLL",
> +        .source     = (XOM_0 ? &xusbxti : &xxti),
> +};
> +
> +
> +/**/
> +static Exynos4210CmuClockState sclk_mpll = {
> +        .name       = "SCLK_MPLL",
> +        .sources    = {XOM_0 ? &xusbxti : &xxti, &mpll},
> +        .src_reg    = CLK_SRC_CPU,
> +        .mux_shift  = MUX_MPLL_SEL_SHIFT,
> +};
> +
> +static Exynos4210CmuClockState sclk_apll = {
> +        .name       = "SCLK_APLL",
> +        .sources    = {XOM_0 ? &xusbxti : &xxti, &apll},
> +        .src_reg    = CLK_SRC_CPU,
> +        .div_reg    = CLK_DIV_CPU0,
> +        .mux_shift  = MUX_APLL_SEL_SHIFT,
> +        .div_shift  = APLL_RATIO_SHIFT,
> +};
> +
> +static Exynos4210CmuClockState aclk_100 = {
> +        .name      = "ACLK_100",
> +        .sources   = {&sclk_mpll, &sclk_apll},
> +        .src_reg   = CLK_SRC_TOP0,
> +        .div_reg   = CLK_DIV_TOP,
> +        .mux_shift = MUX_ACLK_100_SEL_SHIFT,
> +        .div_shift = ACLK_100_RATIO_SHIFT,
> +};
> +
> +
> +/* TODO: add other needed structures for UARTs sources */
> +static Exynos4210CmuClockState sclk_uart0 = {
> +        .name      = "SCLK_UART0",
> +        .sources   = {&xxti, &xusbxti, NULL, NULL, NULL, NULL, &sclk_mpll},
> +        .src_reg   = CLK_SRC_PERIL0,
> +        .div_reg   = CLK_DIV_PERIL0,
> +        .mux_shift = UART0_SEL_SHIFT,
> +        .div_shift = UART0_DIV_SHIFT,
> +};
> +
> +static Exynos4210CmuClockState sclk_uart1 = {
> +        .name      = "SCLK_UART1",
> +        .sources   = {&xxti, &xusbxti, NULL, NULL, NULL, NULL, &sclk_mpll},
> +        .src_reg   = CLK_SRC_PERIL0,
> +        .div_reg   = CLK_DIV_PERIL0,
> +        .mux_shift = UART1_SEL_SHIFT,
> +        .div_shift = UART1_DIV_SHIFT,
> +};
> +
> +static Exynos4210CmuClockState sclk_uart2 = {
> +        .name      = "SCLK_UART2",
> +        .sources   = {&xxti, &xusbxti, NULL, NULL, NULL, NULL, &sclk_mpll},
> +        .src_reg   = CLK_SRC_PERIL0,
> +        .div_reg   = CLK_DIV_PERIL0,
> +        .mux_shift = UART2_SEL_SHIFT,
> +        .div_shift = UART2_DIV_SHIFT,
> +};
> +
> +static Exynos4210CmuClockState sclk_uart3 = {
> +        .name      = "SCLK_UART3",
> +        .sources   = {&xxti, &xusbxti, NULL, NULL, NULL, NULL, &sclk_mpll},
> +        .src_reg   = CLK_SRC_PERIL0,
> +        .div_reg   = CLK_DIV_PERIL0,
> +        .mux_shift = UART3_SEL_SHIFT,
> +        .div_shift = UART3_DIV_SHIFT,
> +};
> +
> +static Exynos4210CmuClockState sclk_uart4 = {
> +        .name      = "SCLK_UART4",
> +        .sources   = {&xxti, &xusbxti, NULL, NULL, NULL, NULL, &sclk_mpll},
> +        .src_reg   = CLK_SRC_PERIL0,
> +        .div_reg   = CLK_DIV_PERIL0,
> +        .mux_shift = UART4_SEL_SHIFT,
> +        .div_shift = UART4_DIV_SHIFT,
> +};
> +
> +/*
> + *  This array must correspond to Exynos4210CmuClock enumerator
> + *  which is defined in exynos4210.h file
> + *
> + */
> +static Exynos4210CmuClockState *exynos4210_clock[] = {
> +        &xxti,
> +        &xusbxti,
> +        &apll,
> +        &mpll,
> +        &sclk_apll,
> +        &sclk_mpll,
> +        &aclk_100,
> +        &sclk_uart0,
> +        &sclk_uart1,
> +        &sclk_uart2,
> +        &sclk_uart3,
> +        &sclk_uart4,
> +        NULL
> +};
> +
> +
> +uint64_t exynos4210_cmu_get_rate(Exynos4210CmuClock clock)
> +{
> +    return exynos4210_clock[clock]->rate;
> +}
> +
> +#ifdef DEBUG_CMU
> +/* The only meaning of life - debugging. This functions should be only used
> + * inside PRINT_DEBUG_... macroses

"This function".
"macros".

> + */
> +static const char *exynos4210_cmu_regname(target_phys_addr_t  offset)
> +{
> +
> +    int regs_number = sizeof(exynos4210_cmu_regs)/sizeof(Exynos4210CmuReg);

int regs_number = ARRAY_SIZE(exynos4210_cmu_regs);

> +    int i;
> +
> +    for (i = 0; i < regs_number; i++) {
> +        if (offset == exynos4210_cmu_regs[i].offset) {
> +            return exynos4210_cmu_regs[i].name;
> +        }
> +    }
> +
> +    return NULL;
> +}
> +#endif
> +
> +static void exynos4210_cmu_set_pll(void *opaque, target_phys_addr_t offset)
> +{
> +    Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
> +    uint32_t pdiv, mdiv, sdiv, enable;
> +
> +    /*
> +     * 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;
> +
> +    switch (offset) {
> +
> +    case MPLL_CON0:
> +        if (mpll.source) {
> +            if (enable) {
> +                mpll.rate = mdiv * mpll.source->rate / (pdiv * (1 << 
> (sdiv-1)));
> +            } else {
> +                mpll.rate = 0;
> +            }
> +        } else {
> +            hw_error("exynos4210_cmu_set_pll: Source undefined for %s\n",
> +                     mpll.name);
> +        }
> +        PRINT_DEBUG("mpll.rate: %llu\n", (unsigned long long int)mpll.rate);
> +        break;
> +
> +    case APLL_CON0:
> +        if (apll.source) {
> +            if (enable) {
> +                apll.rate = mdiv * apll.source->rate / (pdiv * (1 << 
> (sdiv-1)));
> +            } else {
> +                apll.rate = 0;
> +            }
> +        } else {
> +            hw_error("exynos4210_cmu_set_pll: Source undefined for %s\n",
> +                     apll.name);
> +        }
> +        PRINT_DEBUG("apll.rate: %llu\n", (unsigned long long int)apll.rate);
> +        break;
> +
> +    default:
> +        hw_error("exynos4210_cmu_set_pll: Bad offset 0x%x\n", (int)offset);
> +    }
> +
> +    s->reg[I_(offset)] |= PLL_LOCKED_MASK;
> +}
> +
> +
> +static void
> +exynos4210_cmu_set_rate(void *opaque, Exynos4210CmuClockState *clock)
> +{
> +    Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
> +    int i;
> +
> +    /* Rates of PLLs are calculated differently than ordinary clocks rates */
> +    if (clock == &mpll) {
> +        exynos4210_cmu_set_pll(s, MPLL_CON0);
> +    } else if (clock == &apll) {
> +        exynos4210_cmu_set_pll(s, APLL_CON0);
> +    } else if ((clock != &xxti) && (clock != &xusbxti)) {
> +        /*
> +         *  Not root clock. We don't need calculating rate
> +         *  of root clock because it is hard coded.
> +         */
> +        uint32_t src_index = I_(clock->src_reg);
> +        uint32_t div_index = I_(clock->div_reg);
> +        clock->source = clock->sources[(s->reg[src_index] >>
> +                clock->mux_shift) & 0xf];
> +        clock->rate = muldiv64(clock->source->rate, 1,
> +                               (((s->reg[div_index] >> clock->div_shift) & 
> 0xf)
> +                                       + 1));
> +
> +        PRINT_DEBUG_EXTEND("SRC: <0x%05x> %s, SHIFT: %d\n",
> +                           clock->src_reg,
> +                           exynos4210_cmu_regname(clock->src_reg),
> +                           clock->mux_shift);
> +
> +        PRINT_DEBUG("%s [%s:%llu]: %llu\n",
> +                    clock->name,
> +                    clock->source->name,
> +                    (uint64_t)clock->source->rate,
> +                    (uint64_t)clock->rate);
> +    }
> +
> +    /* Visit all recipients for given clock */
> +    i = 0;
> +    do {
> +
> +        Exynos4210CmuClockState *recipient_clock = clock->recipients[i];
> +
> +        if (recipient_clock == NULL) {
> +            PRINT_DEBUG_EXTEND("%s have %d recipients\n", clock->name, i);
> +            break;
> +        }
> +
> +        uint32_t src_index = recipient_clock->src_reg / sizeof(uint32_t);
> +        int source_index = s->reg[src_index] >>
> +                recipient_clock->mux_shift & 0xf;
> +        recipient_clock->source = recipient_clock->sources[source_index];
> +
> +        if (recipient_clock->source != clock) {
> +            break;
> +        }
> +
> +        exynos4210_cmu_set_rate(s, recipient_clock);
> +
> +        i++;
> +    } while (i < RECIPIENTS_NUMBER);
> +}
> +
> +
> +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))) {
> +        hw_error("exynos4210_cmu_read: Bad offset 0x%x\n", (int)offset);
> +    }
> +
> +    PRINT_DEBUG_EXTEND("<0x%05x> %s -> %08x\n", offset,
> +                       exynos4210_cmu_regname(offset), s->reg[I_(offset)]);
> +
> +    return 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 pre_val;
> +
> +    if (offset > (EXYNOS4210_CMU_REGS_MEM_SIZE - sizeof(uint32_t))) {
> +        hw_error("exynos4210_cmu_write: Bad offset 0x%x\n", (int)offset);
> +    }

General rule: don't hw_error() for things a guest can trigger, like writing
to bogus offsets in a device.

> +
> +    pre_val = s->reg[I_(offset)];
> +    s->reg[I_(offset)] = val;
> +
> +    PRINT_DEBUG_EXTEND("<0x%05x> %s <- %08x\n", offset,
> +                       exynos4210_cmu_regname(offset), s->reg[I_(offset)]);
> +
> +    switch (offset) {
> +
> +    case APLL_CON0:
> +        val = (val & ~PLL_LOCKED_MASK) | (pre_val & PLL_LOCKED_MASK);
> +        s->reg[I_(offset)] = val;
> +        exynos4210_cmu_set_rate(s, &apll);
> +        break;
> +    case MPLL_CON0:
> +        val = (val & ~PLL_LOCKED_MASK) | (pre_val & PLL_LOCKED_MASK);
> +        s->reg[I_(offset)] = val;
> +        exynos4210_cmu_set_rate(s, &mpll);
> +        break;
> +    case CLK_SRC_CPU:
> +    {
> +        if (val & MUX_APLL_SEL) {
> +            s->reg[I_(CLK_MUX_STAT_CPU)] =
> +                    (s->reg[I_(CLK_MUX_STAT_CPU)] & ~(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, &apll);
> +            }
> +
> +        } else {
> +            s->reg[I_(CLK_MUX_STAT_CPU)] =
> +                    (s->reg[I_(CLK_MUX_STAT_CPU)] & ~(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 ? &xusbxti : &xxti);
> +            }
> +        }
> +
> +
> +        if (val & MUX_MPLL_SEL) {
> +            s->reg[I_(CLK_MUX_STAT_CPU)] =
> +                    (s->reg[I_(CLK_MUX_STAT_CPU)] & ~(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, &mpll);
> +            }
> +
> +        } else {
> +            s->reg[I_(CLK_MUX_STAT_CPU)] =
> +                    (s->reg[I_(CLK_MUX_STAT_CPU)] & ~(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 ? &xusbxti : &xxti);
> +            }
> +        }
> +
> +        if (val & MUX_CORE_SEL) {
> +            s->reg[I_(CLK_MUX_STAT_CPU)] =
> +                    (s->reg[I_(CLK_MUX_STAT_CPU)] & ~(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, &sclk_mpll);
> +            }
> +
> +        } else {
> +            s->reg[I_(CLK_MUX_STAT_CPU)] =
> +                    (s->reg[I_(CLK_MUX_STAT_CPU)] & ~(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 ? &xusbxti : &xxti);
> +            }
> +        }
> +
> +        if (val & MUX_HPM_SEL) {
> +            exynos4210_cmu_set_rate(s, &sclk_mpll);
> +            s->reg[I_(CLK_MUX_STAT_CPU)] =
> +                    (s->reg[I_(CLK_MUX_STAT_CPU)] & ~(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, &sclk_mpll);
> +            }
> +
> +        } else {
> +            s->reg[I_(CLK_MUX_STAT_CPU)] =
> +                    (s->reg[I_(CLK_MUX_STAT_CPU)] & ~(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 ? &xusbxti : &xxti);
> +            }
> +        }
> +    }
> +    break;
> +    case CLK_DIV_CPU0:
> +        exynos4210_cmu_set_rate(s, &sclk_apll);
> +        exynos4210_cmu_set_rate(s, &sclk_mpll);
> +        break;
> +    case CLK_SRC_TOP0:
> +    case CLK_DIV_TOP:
> +        exynos4210_cmu_set_rate(s, &aclk_100);
> +        break;
> +    default:
> +        break;
> +    }
> +}
> +
> +
> +static const MemoryRegionOps exynos4210_cmu_ops = {
> +        .read = exynos4210_cmu_read,
> +        .write = exynos4210_cmu_write,
> +        .endianness = DEVICE_NATIVE_ENDIAN,
> +};
> +
> +
> +static void exynos4210_cmu_reset(void *opaque)
> +{
> +    Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
> +    int i = 0, j = 0, n = 0;
> +    int regs_number = sizeof(exynos4210_cmu_regs)/sizeof(Exynos4210CmuReg);
> +    uint32_t index = 0;
> +
> +    /* Set default values for registers */
> +    for (i = 0; i < regs_number; i++) {
> +        index = (exynos4210_cmu_regs[i].offset) / sizeof(uint32_t);
> +        s->reg[index] = exynos4210_cmu_regs[i].reset_value;
> +    }
> +
> +    /* clear recipients array from previous reset */
> +    for (i = 0; i < CLOCKS_NUMBER; i++) {
> +        bzero(exynos4210_clock[i]->recipients,
> +              RECIPIENTS_NUMBER * sizeof(Exynos4210CmuClockState *));

bzero() is deprecated. Use memset().

> +    }
> +
> +    /*
> +     * Here we fill '.recipients' fields in all clocks. Also we fill empty
> +     * 'sources[]' arrays by values of 'source' fields (it is necessary
> +     * for set rate, for example). If 'sources[]' array and 'source' field
> +     * is empty simultaneously we get hw_error.
> +     *
> +     */
> +    for (i = 0; i < CLOCKS_NUMBER; i++) {
> +
> +        /* visit all clocks in the exynos4210_clock */
> +
> +        PRINT_DEBUG("[SOURCES] %s: ", exynos4210_clock[i]->name);
> +
> +        j = 0;
> +        do { /* visit all sources for current clock (exynos4210_clock[i]) */
> +
> +            if ((exynos4210_clock[i]->sources[j] == NULL)) {
> +
> +                if (j == 0) { /* check if we have empty '.sources[]' array */
> +                    if (exynos4210_clock[i]->source != NULL) {
> +                        exynos4210_clock[i]->sources[j] =
> +                                exynos4210_clock[i]->source;
> +                    } else {
> +                        /*
> +                         * We haven't any defined sources for this clock. 
> Error
> +                         * during definition of appropriate clock structure
> +                         *
> +                         */
> +                        if ((exynos4210_clock[i] != &xusbxti) &&
> +                            (exynos4210_clock[i] != &xxti)) {
> +
> +                            hw_error("exynos4210_cmu_reset:"
> +                                    "There aren't any sources for %s 
> clock!\n",
> +                                     exynos4210_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 */
> +                }
> +
> +            }
> +
> +            PRINT_DEBUG_SIMPLE(" %s", exynos4210_clock[i]->sources[j]->name);
> +
> +            /*
> +             *  find first empty place in 'recipients[]' array of
> +             *  current 'sources' element and put current clock there
> +             */
> +            n = 0;
> +            do {
> +                if ((exynos4210_clock[i]->sources[j]->recipients[n]) == 
> NULL) {
> +                    exynos4210_clock[i]->sources[j]->recipients[n] =
> +                            exynos4210_clock[i];
> +                    break;
> +                }
> +                n++;
> +            } while (n < RECIPIENTS_NUMBER);

What's wrong with "for (n = 0; n < RECIPIENTS_NUMBER; n++)" ?
(Ditto the loop with j, for that matter.)

> +
> +            j++;
> +
> +        } while (j < SOURCES_NUMBER);
> +
> +        PRINT_DEBUG_SIMPLE("\n");
> +
> +    } /* CLOCKS_NUMBER */
> +
> +#ifdef DEBUG_CMU
> +    for (i = 0; i < CLOCKS_NUMBER; i++) {
> +        PRINT_DEBUG("[RECIPIENTS] %s: ", exynos4210_clock[i]->name);
> +        for (j = 0;
> +             (j < RECIPIENTS_NUMBER) &&
> +             ((exynos4210_clock[i]->recipients[j]) != NULL);
> +             j++) {
> +            PRINT_DEBUG_SIMPLE("%s ", 
> exynos4210_clock[i]->recipients[j]->name);
> +        }
> +        PRINT_DEBUG_SIMPLE("\n");
> +    }
> +#endif
> +
> +    exynos4210_cmu_set_rate(s, XOM_0 ? &xusbxti : &xxti);
> +}
> +
> +static const VMStateDescription vmstate_exynos4210_cmu = {
> +        .name = "exynos4210.cmu",
> +        .version_id = 1,
> +        .minimum_version_id = 1,
> +        .minimum_version_id_old = 1,
> +        .fields = (VMStateField[]) {
> +        /*
> +         * TODO: Maybe we should save Exynos4210CmuClockState structs as well
> +         */

If there's anything in them that can change at runtime (as opposed
to being statically determined at board init time) then yes, it needs
to be saved/restored.

> +            VMSTATE_UINT32_ARRAY(reg, Exynos4210CmuState,
> +                                 EXYNOS4210_CMU_REGS_MEM_SIZE),
> +            VMSTATE_END_OF_LIST()
> +        }
> +};
> +
> +static int exynos4210_cmu_init(SysBusDevice *dev)
> +{
> +    Exynos4210CmuState *s = FROM_SYSBUS(Exynos4210CmuState, dev);
> +
> +    /* memory mapping */
> +    memory_region_init_io(&s->iomem, &exynos4210_cmu_ops, s, 
> "exynos4210.cmu",
> +                          EXYNOS4210_CMU_REGS_MEM_SIZE);
> +    sysbus_init_mmio(dev, &s->iomem);
> +
> +    qemu_register_reset(exynos4210_cmu_reset, s);
> +
> +    vmstate_register(&dev->qdev, -1, &vmstate_exynos4210_cmu, s);

If you use sysbus_register_withprop() rather than sysbus_register_dev()
you can pass the VMState and reset functions as .qdev.vmsd and .qdev.reset
fields in the SysBusDeviceInfo struct.
> +
> +    exynos4210_cmu_reset(s);

You don't need to explicitly call reset here, qdev will do it for you.

> +
> +    return 0;
> +}
> +
> +
> +static void exynos4210_cmu_register(void)
> +{
> +    sysbus_register_dev("exynos4210.cmu",
> +                        sizeof(Exynos4210CmuState),
> +                        exynos4210_cmu_init);
> +}
> +
> +
> +device_init(exynos4210_cmu_register)
> --
> 1.7.4.1
>
>

reply via email to

[Prev in Thread] Current Thread [Next in Thread]