qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

imx25_ccm.c (8491B)


      1 /*
      2  * IMX25 Clock Control Module
      3  *
      4  * Copyright (C) 2012 NICTA
      5  * Updated by Jean-Christophe Dubois <jcd@tribudubois.net>
      6  *
      7  * This work is licensed under the terms of the GNU GPL, version 2 or later.
      8  * See the COPYING file in the top-level directory.
      9  *
     10  * To get the timer frequencies right, we need to emulate at least part of
     11  * the CCM.
     12  */
     13 
     14 #include "qemu/osdep.h"
     15 #include "hw/misc/imx25_ccm.h"
     16 #include "migration/vmstate.h"
     17 #include "qemu/log.h"
     18 #include "qemu/module.h"
     19 
     20 #ifndef DEBUG_IMX25_CCM
     21 #define DEBUG_IMX25_CCM 0
     22 #endif
     23 
     24 #define DPRINTF(fmt, args...) \
     25     do { \
     26         if (DEBUG_IMX25_CCM) { \
     27             fprintf(stderr, "[%s]%s: " fmt , TYPE_IMX25_CCM, \
     28                                              __func__, ##args); \
     29         } \
     30     } while (0)
     31 
     32 static const char *imx25_ccm_reg_name(uint32_t reg)
     33 {
     34     static char unknown[20];
     35 
     36     switch (reg) {
     37     case IMX25_CCM_MPCTL_REG:
     38         return "mpctl";
     39     case IMX25_CCM_UPCTL_REG:
     40         return "upctl";
     41     case IMX25_CCM_CCTL_REG:
     42         return "cctl";
     43     case IMX25_CCM_CGCR0_REG:
     44         return "cgcr0";
     45     case IMX25_CCM_CGCR1_REG:
     46         return "cgcr1";
     47     case IMX25_CCM_CGCR2_REG:
     48         return "cgcr2";
     49     case IMX25_CCM_PCDR0_REG:
     50         return "pcdr0";
     51     case IMX25_CCM_PCDR1_REG:
     52         return "pcdr1";
     53     case IMX25_CCM_PCDR2_REG:
     54         return "pcdr2";
     55     case IMX25_CCM_PCDR3_REG:
     56         return "pcdr3";
     57     case IMX25_CCM_RCSR_REG:
     58         return "rcsr";
     59     case IMX25_CCM_CRDR_REG:
     60         return "crdr";
     61     case IMX25_CCM_DCVR0_REG:
     62         return "dcvr0";
     63     case IMX25_CCM_DCVR1_REG:
     64         return "dcvr1";
     65     case IMX25_CCM_DCVR2_REG:
     66         return "dcvr2";
     67     case IMX25_CCM_DCVR3_REG:
     68         return "dcvr3";
     69     case IMX25_CCM_LTR0_REG:
     70         return "ltr0";
     71     case IMX25_CCM_LTR1_REG:
     72         return "ltr1";
     73     case IMX25_CCM_LTR2_REG:
     74         return "ltr2";
     75     case IMX25_CCM_LTR3_REG:
     76         return "ltr3";
     77     case IMX25_CCM_LTBR0_REG:
     78         return "ltbr0";
     79     case IMX25_CCM_LTBR1_REG:
     80         return "ltbr1";
     81     case IMX25_CCM_PMCR0_REG:
     82         return "pmcr0";
     83     case IMX25_CCM_PMCR1_REG:
     84         return "pmcr1";
     85     case IMX25_CCM_PMCR2_REG:
     86         return "pmcr2";
     87     case IMX25_CCM_MCR_REG:
     88         return "mcr";
     89     case IMX25_CCM_LPIMR0_REG:
     90         return "lpimr0";
     91     case IMX25_CCM_LPIMR1_REG:
     92         return "lpimr1";
     93     default:
     94         sprintf(unknown, "[%u ?]", reg);
     95         return unknown;
     96     }
     97 }
     98 #define CKIH_FREQ 24000000 /* 24MHz crystal input */
     99 
    100 static const VMStateDescription vmstate_imx25_ccm = {
    101     .name = TYPE_IMX25_CCM,
    102     .version_id = 1,
    103     .minimum_version_id = 1,
    104     .fields = (VMStateField[]) {
    105         VMSTATE_UINT32_ARRAY(reg, IMX25CCMState, IMX25_CCM_MAX_REG),
    106         VMSTATE_END_OF_LIST()
    107     },
    108 };
    109 
    110 static uint32_t imx25_ccm_get_mpll_clk(IMXCCMState *dev)
    111 {
    112     uint32_t freq;
    113     IMX25CCMState *s = IMX25_CCM(dev);
    114 
    115     if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], MPLL_BYPASS)) {
    116         freq = CKIH_FREQ;
    117     } else {
    118         freq = imx_ccm_calc_pll(s->reg[IMX25_CCM_MPCTL_REG], CKIH_FREQ);
    119     }
    120 
    121     DPRINTF("freq = %u\n", freq);
    122 
    123     return freq;
    124 }
    125 
    126 static uint32_t imx25_ccm_get_mcu_clk(IMXCCMState *dev)
    127 {
    128     uint32_t freq;
    129     IMX25CCMState *s = IMX25_CCM(dev);
    130 
    131     freq = imx25_ccm_get_mpll_clk(dev);
    132 
    133     if (EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_SRC)) {
    134         freq = (freq * 3 / 4);
    135     }
    136 
    137     freq = freq / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], ARM_CLK_DIV));
    138 
    139     DPRINTF("freq = %u\n", freq);
    140 
    141     return freq;
    142 }
    143 
    144 static uint32_t imx25_ccm_get_ahb_clk(IMXCCMState *dev)
    145 {
    146     uint32_t freq;
    147     IMX25CCMState *s = IMX25_CCM(dev);
    148 
    149     freq = imx25_ccm_get_mcu_clk(dev)
    150            / (1 + EXTRACT(s->reg[IMX25_CCM_CCTL_REG], AHB_CLK_DIV));
    151 
    152     DPRINTF("freq = %u\n", freq);
    153 
    154     return freq;
    155 }
    156 
    157 static uint32_t imx25_ccm_get_ipg_clk(IMXCCMState *dev)
    158 {
    159     uint32_t freq;
    160 
    161     freq = imx25_ccm_get_ahb_clk(dev) / 2;
    162 
    163     DPRINTF("freq = %u\n", freq);
    164 
    165     return freq;
    166 }
    167 
    168 static uint32_t imx25_ccm_get_clock_frequency(IMXCCMState *dev, IMXClk clock)
    169 {
    170     uint32_t freq = 0;
    171     DPRINTF("Clock = %d)\n", clock);
    172 
    173     switch (clock) {
    174     case CLK_NONE:
    175         break;
    176     case CLK_IPG:
    177     case CLK_IPG_HIGH:
    178         freq = imx25_ccm_get_ipg_clk(dev);
    179         break;
    180     case CLK_32k:
    181         freq = CKIL_FREQ;
    182         break;
    183     default:
    184         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: unsupported clock %d\n",
    185                       TYPE_IMX25_CCM, __func__, clock);
    186         break;
    187     }
    188 
    189     DPRINTF("Clock = %d) = %u\n", clock, freq);
    190 
    191     return freq;
    192 }
    193 
    194 static void imx25_ccm_reset(DeviceState *dev)
    195 {
    196     IMX25CCMState *s = IMX25_CCM(dev);
    197 
    198     DPRINTF("\n");
    199 
    200     memset(s->reg, 0, IMX25_CCM_MAX_REG * sizeof(uint32_t));
    201     s->reg[IMX25_CCM_MPCTL_REG] = 0x800b2c01;
    202     s->reg[IMX25_CCM_UPCTL_REG] = 0x84042800;
    203     /* 
    204      * The value below gives:
    205      * CPU = 133 MHz, AHB = 66,5 MHz, IPG = 33 MHz. 
    206      */
    207     s->reg[IMX25_CCM_CCTL_REG]  = 0xd0030000;
    208     s->reg[IMX25_CCM_CGCR0_REG] = 0x028A0100;
    209     s->reg[IMX25_CCM_CGCR1_REG] = 0x04008100;
    210     s->reg[IMX25_CCM_CGCR2_REG] = 0x00000438;
    211     s->reg[IMX25_CCM_PCDR0_REG] = 0x01010101;
    212     s->reg[IMX25_CCM_PCDR1_REG] = 0x01010101;
    213     s->reg[IMX25_CCM_PCDR2_REG] = 0x01010101;
    214     s->reg[IMX25_CCM_PCDR3_REG] = 0x01010101;
    215     s->reg[IMX25_CCM_PMCR0_REG] = 0x00A00000;
    216     s->reg[IMX25_CCM_PMCR1_REG] = 0x0000A030;
    217     s->reg[IMX25_CCM_PMCR2_REG] = 0x0000A030;
    218     s->reg[IMX25_CCM_MCR_REG]   = 0x43000000;
    219 
    220     /*
    221      * default boot will change the reset values to allow:
    222      * CPU = 399 MHz, AHB = 133 MHz, IPG = 66,5 MHz. 
    223      * For some reason, this doesn't work. With the value below, linux
    224      * detects a 88 MHz IPG CLK instead of 66,5 MHz.
    225     s->reg[IMX25_CCM_CCTL_REG]  = 0x20032000;
    226      */
    227 }
    228 
    229 static uint64_t imx25_ccm_read(void *opaque, hwaddr offset, unsigned size)
    230 {
    231     uint32_t value = 0;
    232     IMX25CCMState *s = (IMX25CCMState *)opaque;
    233 
    234     if (offset < 0x70) {
    235         value = s->reg[offset >> 2];
    236     } else {
    237         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    238                       HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
    239     }
    240 
    241     DPRINTF("reg[%s] => 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
    242             value);
    243 
    244     return value;
    245 }
    246 
    247 static void imx25_ccm_write(void *opaque, hwaddr offset, uint64_t value,
    248                             unsigned size)
    249 {
    250     IMX25CCMState *s = (IMX25CCMState *)opaque;
    251 
    252     DPRINTF("reg[%s] <= 0x%" PRIx32 "\n", imx25_ccm_reg_name(offset >> 2),
    253             (uint32_t)value);
    254 
    255     if (offset < 0x70) {
    256         /*
    257          * We will do a better implementation later. In particular some bits
    258          * cannot be written to.
    259          */
    260         s->reg[offset >> 2] = value;
    261     } else {
    262         qemu_log_mask(LOG_GUEST_ERROR, "[%s]%s: Bad register at offset 0x%"
    263                       HWADDR_PRIx "\n", TYPE_IMX25_CCM, __func__, offset);
    264     }
    265 }
    266 
    267 static const struct MemoryRegionOps imx25_ccm_ops = {
    268     .read = imx25_ccm_read,
    269     .write = imx25_ccm_write,
    270     .endianness = DEVICE_NATIVE_ENDIAN,
    271     .valid = {
    272         /*
    273          * Our device would not work correctly if the guest was doing
    274          * unaligned access. This might not be a limitation on the real
    275          * device but in practice there is no reason for a guest to access
    276          * this device unaligned.
    277          */
    278         .min_access_size = 4,
    279         .max_access_size = 4,
    280         .unaligned = false,
    281     },
    282 };
    283 
    284 static void imx25_ccm_init(Object *obj)
    285 {
    286     DeviceState *dev = DEVICE(obj);
    287     SysBusDevice *sd = SYS_BUS_DEVICE(obj);
    288     IMX25CCMState *s = IMX25_CCM(obj);
    289 
    290     memory_region_init_io(&s->iomem, OBJECT(dev), &imx25_ccm_ops, s,
    291                           TYPE_IMX25_CCM, 0x1000);
    292     sysbus_init_mmio(sd, &s->iomem);
    293 }
    294 
    295 static void imx25_ccm_class_init(ObjectClass *klass, void *data)
    296 {
    297     DeviceClass *dc = DEVICE_CLASS(klass);
    298     IMXCCMClass *ccm = IMX_CCM_CLASS(klass);
    299 
    300     dc->reset = imx25_ccm_reset;
    301     dc->vmsd = &vmstate_imx25_ccm;
    302     dc->desc = "i.MX25 Clock Control Module";
    303 
    304     ccm->get_clock_frequency = imx25_ccm_get_clock_frequency;
    305 }
    306 
    307 static const TypeInfo imx25_ccm_info = {
    308     .name          = TYPE_IMX25_CCM,
    309     .parent        = TYPE_IMX_CCM,
    310     .instance_size = sizeof(IMX25CCMState),
    311     .instance_init = imx25_ccm_init,
    312     .class_init    = imx25_ccm_class_init,
    313 };
    314 
    315 static void imx25_ccm_register_types(void)
    316 {
    317     type_register_static(&imx25_ccm_info);
    318 }
    319 
    320 type_init(imx25_ccm_register_types)