+++ /dev/null
-/*
- * Samsung exynos4210 SoC emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
- * Maksim Kozlov <m.kozlov@samsung.com>
- * Evgeny Voevodin <e.voevodin@samsung.com>
- * Igor Mitsyanko <i.mitsyanko@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "boards.h"
-#include "sysemu.h"
-#include "sysbus.h"
-#include "arm-misc.h"
-#include "loader.h"
-#include "exynos4210.h"
-
-#define EXYNOS4210_CHIPID_ADDR 0x10000000
-
-/* PWM */
-#define EXYNOS4210_PWM_BASE_ADDR 0x139D0000
-
-/* RTC */
-#define EXYNOS4210_RTC_BASE_ADDR 0x10070000
-
-/* MCT */
-#define EXYNOS4210_MCT_BASE_ADDR 0x10050000
-
-/* I2C */
-#define EXYNOS4210_I2C_SHIFT 0x00010000
-#define EXYNOS4210_I2C_BASE_ADDR 0x13860000
-/* Interrupt Group of External Interrupt Combiner for I2C */
-#define EXYNOS4210_I2C_INTG 27
-#define EXYNOS4210_HDMI_INTG 16
-
-/* UART's definitions */
-#define EXYNOS4210_UART0_BASE_ADDR 0x13800000
-#define EXYNOS4210_UART1_BASE_ADDR 0x13810000
-#define EXYNOS4210_UART2_BASE_ADDR 0x13820000
-#define EXYNOS4210_UART3_BASE_ADDR 0x13830000
-#define EXYNOS4210_UART0_FIFO_SIZE 256
-#define EXYNOS4210_UART1_FIFO_SIZE 64
-#define EXYNOS4210_UART2_FIFO_SIZE 16
-#define EXYNOS4210_UART3_FIFO_SIZE 16
-/* Interrupt Group of External Interrupt Combiner for UART */
-#define EXYNOS4210_UART_INT_GRP 26
-
-/* External GIC */
-#define EXYNOS4210_EXT_GIC_CPU_BASE_ADDR 0x10480000
-#define EXYNOS4210_EXT_GIC_DIST_BASE_ADDR 0x10490000
-
-/* Combiner */
-#define EXYNOS4210_EXT_COMBINER_BASE_ADDR 0x10440000
-#define EXYNOS4210_INT_COMBINER_BASE_ADDR 0x10448000
-
-/* PMU SFR base address */
-#define EXYNOS4210_PMU_BASE_ADDR 0x10020000
-
-/* Display controllers (FIMD) */
-#define EXYNOS4210_FIMD0_BASE_ADDR 0x11C00000
-
-static uint8_t chipid_and_omr[] = { 0x11, 0x02, 0x21, 0x43,
- 0x09, 0x00, 0x00, 0x00 };
-
-void exynos4210_write_secondary(ARMCPU *cpu,
- const struct arm_boot_info *info)
-{
- int n;
- uint32_t smpboot[] = {
- 0xe59f3024, /* ldr r3, External gic_cpu_if */
- 0xe59f2024, /* ldr r2, Internal gic_cpu_if */
- 0xe59f0024, /* ldr r0, startaddr */
- 0xe3a01001, /* mov r1, #1 */
- 0xe5821000, /* str r1, [r2] */
- 0xe5831000, /* str r1, [r3] */
- 0xe320f003, /* wfi */
- 0xe5901000, /* ldr r1, [r0] */
- 0xe1110001, /* tst r1, r1 */
- 0x0afffffb, /* beq <wfi> */
- 0xe12fff11, /* bx r1 */
- EXYNOS4210_EXT_GIC_CPU_BASE_ADDR,
- 0, /* gic_cpu_if: base address of Internal GIC CPU interface */
- 0 /* bootreg: Boot register address is held here */
- };
- smpboot[ARRAY_SIZE(smpboot) - 1] = info->smp_bootreg_addr;
- smpboot[ARRAY_SIZE(smpboot) - 2] = info->gic_cpu_if_addr;
- for (n = 0; n < ARRAY_SIZE(smpboot); n++) {
- smpboot[n] = tswap32(smpboot[n]);
- }
- rom_add_blob_fixed("smpboot", smpboot, sizeof(smpboot),
- info->smp_loader_start);
-}
-
-Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
- unsigned long ram_size)
-{
- qemu_irq cpu_irq[EXYNOS4210_NCPUS];
- int i, n;
- Exynos4210State *s = g_new(Exynos4210State, 1);
- qemu_irq *irqp;
- qemu_irq gate_irq[EXYNOS4210_NCPUS][EXYNOS4210_IRQ_GATE_NINPUTS];
- unsigned long mem_size;
- DeviceState *dev;
- SysBusDevice *busdev;
-
- for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- s->cpu[n] = cpu_arm_init("cortex-a9");
- if (!s->cpu[n]) {
- fprintf(stderr, "Unable to find CPU %d definition\n", n);
- exit(1);
- }
-
- /* Create PIC controller for each processor instance */
- irqp = arm_pic_init_cpu(s->cpu[n]);
-
- /*
- * Get GICs gpio_in cpu_irq to connect a combiner to them later.
- * Use only IRQ for a while.
- */
- cpu_irq[n] = irqp[ARM_PIC_CPU_IRQ];
- }
-
- /*** IRQs ***/
-
- s->irq_table = exynos4210_init_irq(&s->irqs);
-
- /* IRQ Gate */
- for (i = 0; i < EXYNOS4210_NCPUS; i++) {
- dev = qdev_create(NULL, "exynos4210.irq_gate");
- qdev_prop_set_uint32(dev, "n_in", EXYNOS4210_IRQ_GATE_NINPUTS);
- qdev_init_nofail(dev);
- /* Get IRQ Gate input in gate_irq */
- for (n = 0; n < EXYNOS4210_IRQ_GATE_NINPUTS; n++) {
- gate_irq[i][n] = qdev_get_gpio_in(dev, n);
- }
- busdev = sysbus_from_qdev(dev);
-
- /* Connect IRQ Gate output to cpu_irq */
- sysbus_connect_irq(busdev, 0, cpu_irq[i]);
- }
-
- /* Private memory region and Internal GIC */
- dev = qdev_create(NULL, "a9mpcore_priv");
- qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_SMP_PRIVATE_BASE_ADDR);
- for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- sysbus_connect_irq(busdev, n, gate_irq[n][0]);
- }
- for (n = 0; n < EXYNOS4210_INT_GIC_NIRQ; n++) {
- s->irqs.int_gic_irq[n] = qdev_get_gpio_in(dev, n);
- }
-
- /* Cache controller */
- sysbus_create_simple("l2x0", EXYNOS4210_L2X0_BASE_ADDR, NULL);
-
- /* External GIC */
- dev = qdev_create(NULL, "exynos4210.gic");
- qdev_prop_set_uint32(dev, "num-cpu", EXYNOS4210_NCPUS);
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- /* Map CPU interface */
- sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_GIC_CPU_BASE_ADDR);
- /* Map Distributer interface */
- sysbus_mmio_map(busdev, 1, EXYNOS4210_EXT_GIC_DIST_BASE_ADDR);
- for (n = 0; n < EXYNOS4210_NCPUS; n++) {
- sysbus_connect_irq(busdev, n, gate_irq[n][1]);
- }
- for (n = 0; n < EXYNOS4210_EXT_GIC_NIRQ; n++) {
- s->irqs.ext_gic_irq[n] = qdev_get_gpio_in(dev, n);
- }
-
- /* Internal Interrupt Combiner */
- dev = qdev_create(NULL, "exynos4210.combiner");
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
- sysbus_connect_irq(busdev, n, s->irqs.int_gic_irq[n]);
- }
- exynos4210_combiner_get_gpioin(&s->irqs, dev, 0);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_INT_COMBINER_BASE_ADDR);
-
- /* External Interrupt Combiner */
- dev = qdev_create(NULL, "exynos4210.combiner");
- qdev_prop_set_uint32(dev, "external", 1);
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- for (n = 0; n < EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ; n++) {
- sysbus_connect_irq(busdev, n, s->irqs.ext_gic_irq[n]);
- }
- exynos4210_combiner_get_gpioin(&s->irqs, dev, 1);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_EXT_COMBINER_BASE_ADDR);
-
- /* Initialize board IRQs. */
- exynos4210_init_board_irqs(&s->irqs);
-
- /*** Memory ***/
-
- /* Chip-ID and OMR */
- memory_region_init_ram_ptr(&s->chipid_mem, "exynos4210.chipid",
- sizeof(chipid_and_omr), chipid_and_omr);
- memory_region_set_readonly(&s->chipid_mem, true);
- memory_region_add_subregion(system_mem, EXYNOS4210_CHIPID_ADDR,
- &s->chipid_mem);
-
- /* Internal ROM */
- memory_region_init_ram(&s->irom_mem, "exynos4210.irom",
- EXYNOS4210_IROM_SIZE);
- memory_region_set_readonly(&s->irom_mem, true);
- memory_region_add_subregion(system_mem, EXYNOS4210_IROM_BASE_ADDR,
- &s->irom_mem);
- /* mirror of iROM */
- memory_region_init_alias(&s->irom_alias_mem, "exynos4210.irom_alias",
- &s->irom_mem,
- 0,
- EXYNOS4210_IROM_SIZE);
- memory_region_set_readonly(&s->irom_alias_mem, true);
- memory_region_add_subregion(system_mem, EXYNOS4210_IROM_MIRROR_BASE_ADDR,
- &s->irom_alias_mem);
-
- /* Internal RAM */
- memory_region_init_ram(&s->iram_mem, "exynos4210.iram",
- EXYNOS4210_IRAM_SIZE);
- vmstate_register_ram_global(&s->iram_mem);
- memory_region_add_subregion(system_mem, EXYNOS4210_IRAM_BASE_ADDR,
- &s->iram_mem);
-
- /* DRAM */
- mem_size = ram_size;
- if (mem_size > EXYNOS4210_DRAM_MAX_SIZE) {
- memory_region_init_ram(&s->dram1_mem, "exynos4210.dram1",
- mem_size - EXYNOS4210_DRAM_MAX_SIZE);
- vmstate_register_ram_global(&s->dram1_mem);
- memory_region_add_subregion(system_mem, EXYNOS4210_DRAM1_BASE_ADDR,
- &s->dram1_mem);
- mem_size = EXYNOS4210_DRAM_MAX_SIZE;
- }
- memory_region_init_ram(&s->dram0_mem, "exynos4210.dram0", mem_size);
- vmstate_register_ram_global(&s->dram0_mem);
- memory_region_add_subregion(system_mem, EXYNOS4210_DRAM0_BASE_ADDR,
- &s->dram0_mem);
-
- /* PMU.
- * The only reason of existence at the moment is that secondary CPU boot
- * loader uses PMU INFORM5 register as a holding pen.
- */
- sysbus_create_simple("exynos4210.pmu", EXYNOS4210_PMU_BASE_ADDR, NULL);
-
- /* PWM */
- sysbus_create_varargs("exynos4210.pwm", EXYNOS4210_PWM_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(22, 0)],
- s->irq_table[exynos4210_get_irq(22, 1)],
- s->irq_table[exynos4210_get_irq(22, 2)],
- s->irq_table[exynos4210_get_irq(22, 3)],
- s->irq_table[exynos4210_get_irq(22, 4)],
- NULL);
- /* RTC */
- sysbus_create_varargs("exynos4210.rtc", EXYNOS4210_RTC_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(23, 0)],
- s->irq_table[exynos4210_get_irq(23, 1)],
- NULL);
-
- /* Multi Core Timer */
- dev = qdev_create(NULL, "exynos4210.mct");
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- for (n = 0; n < 4; n++) {
- /* Connect global timer interrupts to Combiner gpio_in */
- sysbus_connect_irq(busdev, n,
- s->irq_table[exynos4210_get_irq(1, 4 + n)]);
- }
- /* Connect local timer interrupts to Combiner gpio_in */
- sysbus_connect_irq(busdev, 4,
- s->irq_table[exynos4210_get_irq(51, 0)]);
- sysbus_connect_irq(busdev, 5,
- s->irq_table[exynos4210_get_irq(35, 3)]);
- sysbus_mmio_map(busdev, 0, EXYNOS4210_MCT_BASE_ADDR);
-
- /*** I2C ***/
- for (n = 0; n < EXYNOS4210_I2C_NUMBER; n++) {
- uint32_t addr = EXYNOS4210_I2C_BASE_ADDR + EXYNOS4210_I2C_SHIFT * n;
- qemu_irq i2c_irq;
-
- if (n < 8) {
- i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_I2C_INTG, n)];
- } else {
- i2c_irq = s->irq_table[exynos4210_get_irq(EXYNOS4210_HDMI_INTG, 1)];
- }
-
- dev = qdev_create(NULL, "exynos4210.i2c");
- qdev_init_nofail(dev);
- busdev = sysbus_from_qdev(dev);
- sysbus_connect_irq(busdev, 0, i2c_irq);
- sysbus_mmio_map(busdev, 0, addr);
- s->i2c_if[n] = (i2c_bus *)qdev_get_child_bus(dev, "i2c");
- }
-
-
- /*** UARTs ***/
- exynos4210_uart_create(EXYNOS4210_UART0_BASE_ADDR,
- EXYNOS4210_UART0_FIFO_SIZE, 0, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 0)]);
-
- exynos4210_uart_create(EXYNOS4210_UART1_BASE_ADDR,
- EXYNOS4210_UART1_FIFO_SIZE, 1, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 1)]);
-
- exynos4210_uart_create(EXYNOS4210_UART2_BASE_ADDR,
- EXYNOS4210_UART2_FIFO_SIZE, 2, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 2)]);
-
- exynos4210_uart_create(EXYNOS4210_UART3_BASE_ADDR,
- EXYNOS4210_UART3_FIFO_SIZE, 3, NULL,
- s->irq_table[exynos4210_get_irq(EXYNOS4210_UART_INT_GRP, 3)]);
-
- /*** Display controller (FIMD) ***/
- sysbus_create_varargs("exynos4210.fimd", EXYNOS4210_FIMD0_BASE_ADDR,
- s->irq_table[exynos4210_get_irq(11, 0)],
- s->irq_table[exynos4210_get_irq(11, 1)],
- s->irq_table[exynos4210_get_irq(11, 2)],
- NULL);
-
- return s;
-}
+++ /dev/null
-/*
- * Samsung exynos4210 SoC emulation
- *
- * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved.
- * Maksim Kozlov <m.kozlov@samsung.com>
- * Evgeny Voevodin <e.voevodin@samsung.com>
- * Igor Mitsyanko <i.mitsyanko@samsung.com>
- *
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-
-#ifndef EXYNOS4210_H_
-#define EXYNOS4210_H_
-
-#include "qemu-common.h"
-#include "memory.h"
-
-#define EXYNOS4210_NCPUS 2
-
-#define EXYNOS4210_DRAM0_BASE_ADDR 0x40000000
-#define EXYNOS4210_DRAM1_BASE_ADDR 0xa0000000
-#define EXYNOS4210_DRAM_MAX_SIZE 0x60000000 /* 1.5 GB */
-
-#define EXYNOS4210_IROM_BASE_ADDR 0x00000000
-#define EXYNOS4210_IROM_SIZE 0x00010000 /* 64 KB */
-#define EXYNOS4210_IROM_MIRROR_BASE_ADDR 0x02000000
-#define EXYNOS4210_IROM_MIRROR_SIZE 0x00010000 /* 64 KB */
-
-#define EXYNOS4210_IRAM_BASE_ADDR 0x02020000
-#define EXYNOS4210_IRAM_SIZE 0x00020000 /* 128 KB */
-
-#define EXYNOS4210_AUDSS_INTMEM_BASE_ADDR 0x03000000
-#define EXYNOS4210_AUDSS_INTMEM_SIZE 0x00039000 /* 228 KB */
-
-#define EXYNOS4210_VPCI_CFG_BASE_ADDR 0xC2000000
-
-/* Secondary CPU startup code is in IROM memory */
-#define EXYNOS4210_SMP_BOOT_ADDR EXYNOS4210_IROM_BASE_ADDR
-#define EXYNOS4210_SMP_BOOT_SIZE 0x1000
-#define EXYNOS4210_BASE_BOOT_ADDR EXYNOS4210_DRAM0_BASE_ADDR
-/* Secondary CPU polling address to get loader start from */
-#define EXYNOS4210_SECOND_CPU_BOOTREG 0x10020814
-
-#define EXYNOS4210_SMP_PRIVATE_BASE_ADDR 0x10500000
-#define EXYNOS4210_L2X0_BASE_ADDR 0x10502000
-
-#define EXYNOS4210_I2C_NUMBER 9
-
-/*
- * exynos4210 IRQ subsystem stub definitions.
- */
-#define EXYNOS4210_IRQ_GATE_NINPUTS 2 /* Internal and External GIC */
-
-#define EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ 64
-#define EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ 16
-#define EXYNOS4210_MAX_INT_COMBINER_IN_IRQ \
- (EXYNOS4210_MAX_INT_COMBINER_OUT_IRQ * 8)
-#define EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ \
- (EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ * 8)
-
-#define EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit) ((grp)*8 + (bit))
-#define EXYNOS4210_COMBINER_GET_GRP_NUM(irq) ((irq) / 8)
-#define EXYNOS4210_COMBINER_GET_BIT_NUM(irq) \
- ((irq) - 8 * EXYNOS4210_COMBINER_GET_GRP_NUM(irq))
-
-/* IRQs number for external and internal GIC */
-#define EXYNOS4210_EXT_GIC_NIRQ (160-32)
-#define EXYNOS4210_INT_GIC_NIRQ 64
-
-#define EXYNOS4210_I2C_NUMBER 9
-
-typedef struct Exynos4210Irq {
- qemu_irq int_combiner_irq[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ];
- qemu_irq ext_combiner_irq[EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ];
- qemu_irq int_gic_irq[EXYNOS4210_INT_GIC_NIRQ];
- qemu_irq ext_gic_irq[EXYNOS4210_EXT_GIC_NIRQ];
- qemu_irq board_irqs[EXYNOS4210_MAX_INT_COMBINER_IN_IRQ];
-} Exynos4210Irq;
-
-typedef struct Exynos4210State {
- ARMCPU *cpu[EXYNOS4210_NCPUS];
- Exynos4210Irq irqs;
- qemu_irq *irq_table;
-
- MemoryRegion chipid_mem;
- MemoryRegion iram_mem;
- MemoryRegion irom_mem;
- MemoryRegion irom_alias_mem;
- MemoryRegion dram0_mem;
- MemoryRegion dram1_mem;
- MemoryRegion boot_secondary;
- MemoryRegion bootreg_mem;
- MemoryRegion audss_intmem;
- i2c_bus *i2c_if[EXYNOS4210_I2C_NUMBER];
- BusState *i2s_bus[3];
- SysBusDevice *vpci_bus;
-} Exynos4210State;
-
-void exynos4210_write_secondary(ARMCPU *cpu,
- const struct arm_boot_info *info);
-
-Exynos4210State *exynos4210_init(MemoryRegion *system_mem,
- unsigned long ram_size);
-
-/* Initialize exynos4210 IRQ subsystem stub */
-qemu_irq *exynos4210_init_irq(Exynos4210Irq *env);
-
-/* Initialize board IRQs.
- * These IRQs contain splitted Int/External Combiner and External Gic IRQs */
-void exynos4210_init_board_irqs(Exynos4210Irq *s);
-
-/* Get IRQ number from exynos4210 IRQ subsystem stub.
- * To identify IRQ source use internal combiner group and bit number
- * grp - group number
- * bit - bit number inside group */
-uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit);
-
-/*
- * Get Combiner input GPIO into irqs structure
- */
-void exynos4210_combiner_get_gpioin(Exynos4210Irq *irqs, DeviceState *dev,
- int ext);
-
-/*
- * Interface for exynos4210 Clock Management Units (CMUs)
- */
-typedef enum {
- UNSPECIFIED_CMU = -1,
- EXYNOS4210_CMU_LEFTBUS,
- EXYNOS4210_CMU_RIGHTBUS,
- EXYNOS4210_CMU_TOP,
- EXYNOS4210_CMU_DMC,
- EXYNOS4210_CMU_CPU,
- EXYNOS4210_CMU_NUMBER
-} Exynos4210Cmu;
-
-typedef enum {
- UNSPECIFIED_CLOCK,
- EXYNOS4210_XXTI,
- EXYNOS4210_XUSBXTI,
-// EXYNOS4210_USB_PHY,
-// EXYNOS4210_USB_HOST_PHY,
-// EXYNOS4210_HDMI_PHY,
- EXYNOS4210_APLL,
- EXYNOS4210_MPLL,
- EXYNOS4210_SCLK_HDMI24M,
- EXYNOS4210_SCLK_USBPHY0,
- EXYNOS4210_SCLK_USBPHY1,
- EXYNOS4210_SCLK_HDMIPHY,
- EXYNOS4210_SCLK_APLL,
- EXYNOS4210_SCLK_MPLL,
- EXYNOS4210_ACLK_100,
- EXYNOS4210_SCLK_UART0,
- EXYNOS4210_SCLK_UART1,
- EXYNOS4210_SCLK_UART2,
- EXYNOS4210_SCLK_UART3,
- EXYNOS4210_SCLK_UART4,
- EXYNOS4210_CLOCKS_NUMBER
-} Exynos4210Clock;
-
-typedef void ClockChangeHandler(void *opaque);
-
-DeviceState *exynos4210_cmu_create(target_phys_addr_t addr, Exynos4210Cmu cmu);
-uint64_t exynos4210_cmu_get_rate(Exynos4210Clock clock_id);
-void exynos4210_register_clock_handler(ClockChangeHandler *func,
- Exynos4210Clock clock_id,
- void *opaque);
-
-/*
- * exynos4210 UART
- */
-DeviceState *exynos4210_uart_create(target_phys_addr_t addr,
- int fifo_size,
- int channel,
- CharDriverState *chr,
- qemu_irq irq);
-
-#endif /* EXYNOS4210_H_ */
+++ /dev/null
-/*
- * Samsung exynos4210 Audio driver
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Vorobiov Stanislav <s.vorobiov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "exynos4210_i2s.h"
-#include "wm8994.h"
-
-/* #define DEBUG_EXYNOS4210_AUDIO */
-
-#ifdef DEBUG_EXYNOS4210_AUDIO
-#define DPRINTF(fmt, ...) \
- do { \
- fprintf(stdout, "AUDIO: [%s:%d] " fmt, __func__, __LINE__, \
- ## __VA_ARGS__); \
- } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-#define AUDIO_MAX_WORDS (4096 / EXYNOS4210_I2S_WORD_LEN)
-
-typedef struct {
- Exynos4210I2SSlave i2s;
-
- DeviceState *wm8994;
-} Exynos4210AudioState;
-
-static void exynos4210_audio_callback(void *opaque, int free_out_bytes)
-{
- Exynos4210AudioState *s = (Exynos4210AudioState *)opaque;
- uint8_t buff[AUDIO_MAX_WORDS * EXYNOS4210_I2S_WORD_LEN];
- int free_out_words = free_out_bytes / EXYNOS4210_I2S_WORD_LEN;
- uint32_t num_words;
-
- if (free_out_words <= 0) {
- return;
- }
-
- if (free_out_words > AUDIO_MAX_WORDS) {
- free_out_words = AUDIO_MAX_WORDS;
- }
-
- if (!exynos4210_i2s_dma_enabled(qdev_get_parent_bus(&s->i2s.qdev))) {
- return;
- }
-
- num_words = exynos4210_i2s_dma_get_words_available(
- qdev_get_parent_bus(&s->i2s.qdev));
-
- num_words = MIN(num_words, free_out_words);
-
- exynos4210_i2s_dma_read(qdev_get_parent_bus(&s->i2s.qdev),
- &buff[0],
- num_words);
-
- num_words = wm8994_dac_write(s->wm8994,
- &buff[0],
- num_words * EXYNOS4210_I2S_WORD_LEN) / EXYNOS4210_I2S_WORD_LEN;
-
- exynos4210_i2s_dma_advance(qdev_get_parent_bus(&s->i2s.qdev), num_words);
-}
-
-static void exynos4210_audio_dma_enable(Exynos4210I2SSlave *i2s, bool enable)
-{
- Exynos4210AudioState *s =
- FROM_EXYNOS4210_I2S_SLAVE(Exynos4210AudioState, i2s);
-
- DPRINTF("enter %d\n", enable);
-
- wm8994_set_active(s->wm8994, enable);
-}
-
-static void exynos4210_audio_reset(DeviceState *dev)
-{
- DPRINTF("enter\n");
-}
-
-static int exynos4210_audio_init(Exynos4210I2SSlave *i2s)
-{
- Exynos4210AudioState *s =
- FROM_EXYNOS4210_I2S_SLAVE(Exynos4210AudioState, i2s);
-
- wm8994_data_req_set(s->wm8994, exynos4210_audio_callback, s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_exynos4210_audio = {
- .name = "exynos4210.audio",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_EXYNOS4210_I2S_SLAVE(i2s, Exynos4210AudioState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static Property exynos4210_audio_properties[] = {
- {
- .name = "wm8994",
- .info = &qdev_prop_ptr,
- .offset = offsetof(Exynos4210AudioState, wm8994),
- },
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_audio_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- Exynos4210I2SSlaveClass *sc = EXYNOS4210_I2S_SLAVE_CLASS(klass);
-
- sc->init = exynos4210_audio_init;
- sc->dma_enable = exynos4210_audio_dma_enable;
- dc->reset = exynos4210_audio_reset;
- dc->props = exynos4210_audio_properties;
- dc->vmsd = &vmstate_exynos4210_audio;
-}
-
-static TypeInfo exynos4210_audio_info = {
- .name = "exynos4210.audio",
- .parent = TYPE_EXYNOS4210_I2S_SLAVE,
- .instance_size = sizeof(Exynos4210AudioState),
- .class_init = exynos4210_audio_class_init,
-};
-
-static void exynos4210_audio_register_types(void)
-{
- type_register_static(&exynos4210_audio_info);
-}
-
-type_init(exynos4210_audio_register_types)
+++ /dev/null
-/*
- * exynos4210 Clock Management Units (CMUs) Emulation
- *
- * Copyright (C) 2011 Samsung Electronics Co Ltd.
- * Maksim Kozlov, <m.kozlov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "sysbus.h"
-
-#include "exynos4210.h"
-
-
-
-#define DEBUG_CMU 0
-#define DEBUG_CMU_EXTEND 0
-
-#if DEBUG_CMU || DEBUG_CMU_EXTEND
-
- #define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
- #define PRINT_DEBUG_SIMPLE(fmt, args...) \
- do { \
- fprintf(stderr, fmt, ## args); \
- } while (0)
-
-#if DEBUG_CMU_EXTEND
-
- #define PRINT_DEBUG_EXTEND(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-#else
- #define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif /* EXTEND */
-
-#else
- #define PRINT_DEBUG(fmt, args...) \
- do {} while (0)
- #define PRINT_DEBUG_SIMPLE(fmt, args...) \
- do {} while (0)
- #define PRINT_DEBUG_EXTEND(fmt, args...) \
- do {} while (0)
-#endif
-
-#define PRINT_ERROR(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-
-
-/* function blocks */
-#define LEFTBUS_BLK 0x0
-#define RIGHTBUS_BLK 0x0
-#define TOP_BLK 0x10
-#define TOP0_BLK 0x10
-#define TOP1_BLK 0x14
-#define DMC_BLK 0x0
-#define DMC0_BLK 0x0
-#define DMC1_BLK 0x4
-#define CPU_BLK 0x0
-#define CPU0_BLK 0x0
-#define CPU1_BLK 0x4
-
-#define CAM_BLK 0x20
-#define TV_BLK 0x24
-#define MFC_BLK 0x28
-#define G3D_BLK 0x2C
-#define IMAGE_BLK 0x30
-#define LCD0_BLK 0x34
-#define LCD1_BLK 0x38
-#define MAUDIO_BLK 0x3C
-#define FSYS_BLK 0x40
-#define FSYS0_BLK 0x40
-#define FSYS1_BLK 0x44
-#define FSYS2_BLK 0x48
-#define FSYS3_BLK 0x4C
-#define GPS_BLK 0x4C /* CLK_GATE_IP_GPS in CMU_TOP */
-#define PERIL_BLK 0x50
-#define PERIL0_BLK 0x50
-#define PERIL1_BLK 0x54
-#define PERIL2_BLK 0x58
-#define PERIL3_BLK 0x5C
-#define PERIL4_BLK 0x60
-#define PERIR_BLK 0x60 /* CLK_GATE_IP_PERIR in CMU_TOP */
-#define PERIL5_BLK 0x64
-
-#define BLOCK_MASK 0xFF
-
-/* PLLs */
-/* located in CMU_CPU block */
-#define APLL 0x00
-#define MPLL 0x08
-/* located in CMU_TOP block */
-#define EPLL 0x10
-#define VPLL 0x20
-
-/* groups of registers */
-#define PLL_LOCK 0x000
-#define PLL_CON 0x100
-#define CLK_SRC 0x200
-#define CLK_SRC_MASK 0x300
-#define CLK_MUX_STAT 0x400
-#define CLK_DIV 0x500
-#define CLK_DIV_STAT 0x600
-#define CLK_GATE_SCLK 0x800
-#define CLK_GATE_IP 0x900
-
-#define GROUP_MASK 0xF00
-
-#define PLL_LOCK_(pll) (PLL_LOCK + pll)
-#define PLL_CON0_(pll) (PLL_CON + pll)
-#define PLL_CON1_(pll) (PLL_CON + pll + 4)
-
-#define CLK_SRC_(block) (CLK_SRC + block)
-#define CLK_SRC_MASK_(block) (CLK_SRC_MASK + block)
-#define CLK_MUX_STAT_(block) (CLK_MUX_STAT + block)
-#define CLK_DIV_(block) (CLK_DIV + block)
-#define CLKDIV2_RATIO 0x580 /* described for CMU_TOP only */
-#define CLK_DIV_STAT_(block) (CLK_DIV_STAT + block)
-#define CLKDIV2_STAT 0x680 /* described for CMU_TOP only */
-#define CLK_GATE_SCLK_(block) (CLK_GATE_SCLK + block)
-/* For CMU_LEFTBUS and CMU_RIGHTBUS, CLK_GATE_IP_XXX
- registers are located at 0x800. */
-#define CLK_GATE_IP_LR_BUS 0x800
-#define CLK_GATE_IP_(block) (CLK_GATE_IP + block)
-#define CLK_GATE_BLOCK 0x970 /* described for CMU_TOP only */
-#define CLKOUT_CMU 0xA00
-#define CLKOUT_CMU_DIV_STAT 0xA04
-
-/*
- * registers which are located outside of 0xAFF region
- */
-/* CMU_DMC */
-#define DCGIDX_MAP0 0x01000
-#define DCGIDX_MAP1 0x01004
-#define DCGIDX_MAP2 0x01008
-#define DCGPERF_MAP0 0x01020
-#define DCGPERF_MAP1 0x01024
-#define DVCIDX_MAP 0x01040
-#define FREQ_CPU 0x01060
-#define FREQ_DPM 0x01064
-#define DVSEMCLK_EN 0x01080
-#define MAXPERF 0x01084
-/* CMU_CPU */
-#define ARMCLK_STOPCTRL 0x01000
-#define ATCLK_STOPCTRL 0x01004
-#define PARITYFAIL_STATUS 0x01010
-#define PARITYFAIL_CLEAR 0x01014
-#define PWR_CTRL 0x01020
-#define APLL_CON0_L8 0x01100
-#define APLL_CON0_L7 0x01104
-#define APLL_CON0_L6 0x01108
-#define APLL_CON0_L5 0x0110C
-#define APLL_CON0_L4 0x01110
-#define APLL_CON0_L3 0x01114
-#define APLL_CON0_L2 0x01118
-#define APLL_CON0_L1 0x0111C
-#define IEM_CONTROL 0x01120
-#define APLL_CON1_L8 0x01200
-#define APLL_CON1_L7 0x01204
-#define APLL_CON1_L6 0x01208
-#define APLL_CON1_L5 0x0120C
-#define APLL_CON1_L4 0x01210
-#define APLL_CON1_L3 0x01214
-#define APLL_CON1_L2 0x01218
-#define APLL_CON1_L1 0x0121C
-#define CLKDIV_IEM_L8 0x01300
-#define CLKDIV_IEM_L7 0x01304
-#define CLKDIV_IEM_L6 0x01308
-#define CLKDIV_IEM_L5 0x0130C
-#define CLKDIV_IEM_L4 0x01310
-#define CLKDIV_IEM_L3 0x01314
-#define CLKDIV_IEM_L2 0x01318
-#define CLKDIV_IEM_L1 0x0131C
-
-#define EXTENDED_REGION_MASK 0x1000
-#define EXTENDED_REGISTER_MASK 0xFFF
-
-typedef struct {
- const char *name; /* for debugging */
- uint32_t offset;
- uint32_t reset_value;
-} Exynos4210CmuReg;
-
-
-static Exynos4210CmuReg exynos4210_cmu_leftbus_regs[] = {
- /* CMU_LEFTBUS registers */
- {"CLK_SRC_LEFTBUS", CLK_SRC_(LEFTBUS_BLK), 0x00000000},
- {"CLK_MUX_STAT_LEFTBUS", CLK_MUX_STAT_(LEFTBUS_BLK), 0x00000001},
- {"CLK_DIV_LEFTBUS", CLK_DIV_(LEFTBUS_BLK), 0x00000000},
- {"CLK_DIV_STAT_LEFTBUS", CLK_DIV_STAT_(LEFTBUS_BLK), 0x00000000},
- {"CLK_GATE_IP_LEFTBUS", CLK_GATE_IP_LR_BUS, 0xFFFFFFFF},
- {"CLKOUT_CMU_LEFTBUS", CLKOUT_CMU, 0x00010000},
- {"CLKOUT_CMU_LEFTBUS_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000},
-};
-
-static Exynos4210CmuReg exynos4210_cmu_rightbus_regs[] = {
- /* CMU_RIGHTBUS registers */
- {"CLK_SRC_RIGHTBUS", CLK_SRC_(RIGHTBUS_BLK), 0x00000000},
- {"CLK_MUX_STAT_RIGHTBUS", CLK_MUX_STAT_(RIGHTBUS_BLK), 0x00000001},
- {"CLK_DIV_RIGHTBUS", CLK_DIV_(RIGHTBUS_BLK), 0x00000000},
- {"CLK_DIV_STAT_RIGHTBUS", CLK_DIV_STAT_(RIGHTBUS_BLK), 0x00000000},
- {"CLK_GATE_IP_RIGHTBUS", CLK_GATE_IP_LR_BUS, 0xFFFFFFFF},
- {"CLKOUT_CMU_RIGHTBUS", CLKOUT_CMU, 0x00010000},
- {"CLKOUT_CMU_RIGHTBUS_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000},
-};
-
-static Exynos4210CmuReg exynos4210_cmu_top_regs[] = {
- /* CMU_TOP registers */
- {"EPLL_LOCK", PLL_LOCK_(EPLL), 0x00000FFF},
- {"VPLL_LOCK", PLL_LOCK_(VPLL), 0x00000FFF},
- {"EPLL_CON0", PLL_CON0_(EPLL), 0x00300301},
- {"EPLL_CON1", PLL_CON1_(EPLL), 0x00000000},
- {"VPLL_CON0", PLL_CON0_(VPLL), 0x00240201},
- {"VPLL_CON1", PLL_CON1_(VPLL), 0x66010464},
- {"CLK_SRC_TOP0", CLK_SRC_(TOP0_BLK), 0x00000000},
- {"CLK_SRC_TOP1", CLK_SRC_(TOP1_BLK), 0x00000000},
- {"CLK_SRC_CAM", CLK_SRC_(CAM_BLK), 0x11111111},
- {"CLK_SRC_TV", CLK_SRC_(TV_BLK), 0x00000000},
- {"CLK_SRC_MFC", CLK_SRC_(MFC_BLK), 0x00000000},
- {"CLK_SRC_G3D", CLK_SRC_(G3D_BLK), 0x00000000},
- {"CLK_SRC_IMAGE", CLK_SRC_(IMAGE_BLK), 0x00000000},
- {"CLK_SRC_LCD0", CLK_SRC_(LCD0_BLK), 0x00001111},
- {"CLK_SRC_LCD1", CLK_SRC_(LCD1_BLK), 0x00001111},
- {"CLK_SRC_MAUDIO", CLK_SRC_(MAUDIO_BLK), 0x00000005},
- {"CLK_SRC_FSYS", CLK_SRC_(FSYS_BLK), 0x00011111},
- {"CLK_SRC_PERIL0", CLK_SRC_(PERIL0_BLK), 0x00011111},
- {"CLK_SRC_PERIL1", CLK_SRC_(PERIL1_BLK), 0x01110055},
- {"CLK_SRC_MASK_TOP", CLK_SRC_MASK_(TOP_BLK), 0x00000001},
- {"CLK_SRC_MASK_CAM", CLK_SRC_MASK_(CAM_BLK), 0x11111111},
- {"CLK_SRC_MASK_TV", CLK_SRC_MASK_(TV_BLK), 0x00000111},
- {"CLK_SRC_MASK_LCD0", CLK_SRC_MASK_(LCD0_BLK), 0x00001111},
- {"CLK_SRC_MASK_LCD1", CLK_SRC_MASK_(LCD1_BLK), 0x00001111},
- {"CLK_SRC_MASK_MAUDIO", CLK_SRC_MASK_(MAUDIO_BLK), 0x00000001},
- {"CLK_SRC_MASK_FSYS", CLK_SRC_MASK_(FSYS_BLK), 0x01011111},
- {"CLK_SRC_MASK_PERIL0", CLK_SRC_MASK_(PERIL0_BLK), 0x00011111},
- {"CLK_SRC_MASK_PERIL1", CLK_SRC_MASK_(PERIL1_BLK), 0x01110111},
- {"CLK_MUX_STAT_TOP", CLK_MUX_STAT_(TOP_BLK), 0x11111111},
- {"CLK_MUX_STAT_MFC", CLK_MUX_STAT_(MFC_BLK), 0x00000111},
- {"CLK_MUX_STAT_G3D", CLK_MUX_STAT_(G3D_BLK), 0x00000111},
- {"CLK_MUX_STAT_IMAGE", CLK_MUX_STAT_(IMAGE_BLK), 0x00000111},
- {"CLK_DIV_TOP", CLK_DIV_(TOP_BLK), 0x00000000},
- {"CLK_DIV_CAM", CLK_DIV_(CAM_BLK), 0x00000000},
- {"CLK_DIV_TV", CLK_DIV_(TV_BLK), 0x00000000},
- {"CLK_DIV_MFC", CLK_DIV_(MFC_BLK), 0x00000000},
- {"CLK_DIV_G3D", CLK_DIV_(G3D_BLK), 0x00000000},
- {"CLK_DIV_IMAGE", CLK_DIV_(IMAGE_BLK), 0x00000000},
- {"CLK_DIV_LCD0", CLK_DIV_(LCD0_BLK), 0x00700000},
- {"CLK_DIV_LCD1", CLK_DIV_(LCD1_BLK), 0x00700000},
- {"CLK_DIV_MAUDIO", CLK_DIV_(MAUDIO_BLK), 0x00000000},
- {"CLK_DIV_FSYS0", CLK_DIV_(FSYS0_BLK), 0x00B00000},
- {"CLK_DIV_FSYS1", CLK_DIV_(FSYS1_BLK), 0x00000000},
- {"CLK_DIV_FSYS2", CLK_DIV_(FSYS2_BLK), 0x00000000},
- {"CLK_DIV_FSYS3", CLK_DIV_(FSYS3_BLK), 0x00000000},
- {"CLK_DIV_PERIL0", CLK_DIV_(PERIL0_BLK), 0x00000000},
- {"CLK_DIV_PERIL1", CLK_DIV_(PERIL1_BLK), 0x00000000},
- {"CLK_DIV_PERIL2", CLK_DIV_(PERIL2_BLK), 0x00000000},
- {"CLK_DIV_PERIL3", CLK_DIV_(PERIL3_BLK), 0x00000000},
- {"CLK_DIV_PERIL4", CLK_DIV_(PERIL4_BLK), 0x00000000},
- {"CLK_DIV_PERIL5", CLK_DIV_(PERIL5_BLK), 0x00000000},
- {"CLKDIV2_RATIO", CLKDIV2_RATIO, 0x11111111},
- {"CLK_DIV_STAT_TOP", CLK_DIV_STAT_(TOP_BLK), 0x00000000},
- {"CLK_DIV_STAT_CAM", CLK_DIV_STAT_(CAM_BLK), 0x00000000},
- {"CLK_DIV_STAT_TV", CLK_DIV_STAT_(TV_BLK), 0x00000000},
- {"CLK_DIV_STAT_MFC", CLK_DIV_STAT_(MFC_BLK), 0x00000000},
- {"CLK_DIV_STAT_G3D", CLK_DIV_STAT_(G3D_BLK), 0x00000000},
- {"CLK_DIV_STAT_IMAGE", CLK_DIV_STAT_(IMAGE_BLK), 0x00000000},
- {"CLK_DIV_STAT_LCD0", CLK_DIV_STAT_(LCD0_BLK), 0x00000000},
- {"CLK_DIV_STAT_LCD1", CLK_DIV_STAT_(LCD1_BLK), 0x00000000},
- {"CLK_DIV_STAT_MAUDIO", CLK_DIV_STAT_(MAUDIO_BLK), 0x00000000},
- {"CLK_DIV_STAT_FSYS0", CLK_DIV_STAT_(FSYS0_BLK), 0x00000000},
- {"CLK_DIV_STAT_FSYS1", CLK_DIV_STAT_(FSYS1_BLK), 0x00000000},
- {"CLK_DIV_STAT_FSYS2", CLK_DIV_STAT_(FSYS2_BLK), 0x00000000},
- {"CLK_DIV_STAT_FSYS3", CLK_DIV_STAT_(FSYS3_BLK), 0x00000000},
- {"CLK_DIV_STAT_PERIL0", CLK_DIV_STAT_(PERIL0_BLK), 0x00000000},
- {"CLK_DIV_STAT_PERIL1", CLK_DIV_STAT_(PERIL1_BLK), 0x00000000},
- {"CLK_DIV_STAT_PERIL2", CLK_DIV_STAT_(PERIL2_BLK), 0x00000000},
- {"CLK_DIV_STAT_PERIL3", CLK_DIV_STAT_(PERIL3_BLK), 0x00000000},
- {"CLK_DIV_STAT_PERIL4", CLK_DIV_STAT_(PERIL4_BLK), 0x00000000},
- {"CLK_DIV_STAT_PERIL5", CLK_DIV_STAT_(PERIL5_BLK), 0x00000000},
- {"CLKDIV2_STAT", CLKDIV2_STAT, 0x00000000},
- {"CLK_GATE_SCLK_CAM", CLK_GATE_SCLK_(CAM_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_CAM", CLK_GATE_IP_(CAM_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_TV", CLK_GATE_IP_(TV_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_MFC", CLK_GATE_IP_(MFC_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_G3D", CLK_GATE_IP_(G3D_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_IMAGE", CLK_GATE_IP_(IMAGE_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_LCD0", CLK_GATE_IP_(LCD0_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_LCD1", CLK_GATE_IP_(LCD1_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_FSYS", CLK_GATE_IP_(FSYS_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_GPS", CLK_GATE_IP_(GPS_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_PERIL", CLK_GATE_IP_(PERIL_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_PERIR", CLK_GATE_IP_(PERIR_BLK), 0xFFFFFFFF},
- {"CLK_GATE_BLOCK", CLK_GATE_BLOCK, 0xFFFFFFFF},
- {"CLKOUT_CMU_TOP", CLKOUT_CMU, 0x00010000},
- {"CLKOUT_CMU_TOP_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000},
-};
-
-static Exynos4210CmuReg exynos4210_cmu_dmc_regs[] = {
- /* CMU_DMC registers */
- {"CLK_SRC_DMC", CLK_SRC_(DMC_BLK), 0x00010000},
- {"CLK_SRC_MASK_DMC", CLK_SRC_MASK_(DMC_BLK), 0x00010000},
- {"CLK_MUX_STAT_DMC", CLK_MUX_STAT_(DMC_BLK), 0x11100110},
- {"CLK_DIV_DMC0", CLK_DIV_(DMC0_BLK), 0x00000000},
- {"CLK_DIV_DMC1", CLK_DIV_(DMC1_BLK), 0x00000000},
- {"CLK_DIV_STAT_DMC0", CLK_DIV_STAT_(DMC0_BLK), 0x00000000},
- {"CLK_DIV_STAT_DMC1", CLK_DIV_STAT_(DMC1_BLK), 0x00000000},
- {"CLK_GATE_IP_DMC", CLK_GATE_IP_(DMC_BLK), 0xFFFFFFFF},
- {"CLKOUT_CMU_DMC", CLKOUT_CMU, 0x00010000},
- {"CLKOUT_CMU_DMC_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000},
- {"DCGIDX_MAP0", DCGIDX_MAP0, 0xFFFFFFFF},
- {"DCGIDX_MAP1", DCGIDX_MAP1, 0xFFFFFFFF},
- {"DCGIDX_MAP2", DCGIDX_MAP2, 0xFFFFFFFF},
- {"DCGPERF_MAP0", DCGPERF_MAP0, 0xFFFFFFFF},
- {"DCGPERF_MAP1", DCGPERF_MAP1, 0xFFFFFFFF},
- {"DVCIDX_MAP", DVCIDX_MAP, 0xFFFFFFFF},
- {"FREQ_CPU", FREQ_CPU, 0x00000000},
- {"FREQ_DPM", FREQ_DPM, 0x00000000},
- {"DVSEMCLK_EN", DVSEMCLK_EN, 0x00000000},
- {"MAXPERF", MAXPERF, 0x00000000},
-};
-
-static Exynos4210CmuReg exynos4210_cmu_cpu_regs[] = {
- /* CMU_CPU registers */
- {"APLL_LOCK", PLL_LOCK_(APLL), 0x00000FFF},
- {"MPLL_LOCK", PLL_LOCK_(MPLL), 0x00000FFF},
- {"APLL_CON0", PLL_CON0_(APLL), 0x00C80601},
- {"APLL_CON1", PLL_CON1_(APLL), 0x0000001C},
- {"MPLL_CON0", PLL_CON0_(MPLL), 0x00C80601},
- {"MPLL_CON1", PLL_CON1_(MPLL), 0x0000001C},
- {"CLK_SRC_CPU", CLK_SRC_(CPU_BLK), 0x00000000},
- {"CLK_MUX_STAT_CPU", CLK_MUX_STAT_(CPU_BLK), 0x00110101},
- {"CLK_DIV_CPU0", CLK_DIV_(CPU0_BLK), 0x00000000},
- {"CLK_DIV_CPU1", CLK_DIV_(CPU1_BLK), 0x00000000},
- {"CLK_DIV_STAT_CPU0", CLK_DIV_STAT_(CPU0_BLK), 0x00000000},
- {"CLK_DIV_STAT_CPU1", CLK_DIV_STAT_(CPU1_BLK), 0x00000000},
- {"CLK_GATE_SCLK_CPU", CLK_GATE_SCLK_(CPU_BLK), 0xFFFFFFFF},
- {"CLK_GATE_IP_CPU", CLK_GATE_IP_(CPU_BLK), 0xFFFFFFFF},
- {"CLKOUT_CMU_CPU", CLKOUT_CMU, 0x00010000},
- {"CLKOUT_CMU_CPU_DIV_STAT", CLKOUT_CMU_DIV_STAT, 0x00000000},
- {"ARMCLK_STOPCTRL", ARMCLK_STOPCTRL, 0x00000044},
- {"ATCLK_STOPCTRL", ATCLK_STOPCTRL, 0x00000044},
- {"PARITYFAIL_STATUS", PARITYFAIL_STATUS, 0x00000000},
- {"PARITYFAIL_CLEAR", PARITYFAIL_CLEAR, 0x00000000},
- {"PWR_CTRL", PWR_CTRL, 0x00000033},
- {"APLL_CON0_L8", APLL_CON0_L8, 0x00C80601},
- {"APLL_CON0_L7", APLL_CON0_L7, 0x00C80601},
- {"APLL_CON0_L6", APLL_CON0_L6, 0x00C80601},
- {"APLL_CON0_L5", APLL_CON0_L5, 0x00C80601},
- {"APLL_CON0_L4", APLL_CON0_L4, 0x00C80601},
- {"APLL_CON0_L3", APLL_CON0_L3, 0x00C80601},
- {"APLL_CON0_L2", APLL_CON0_L2, 0x00C80601},
- {"APLL_CON0_L1", APLL_CON0_L1, 0x00C80601},
- {"IEM_CONTROL", IEM_CONTROL, 0x00000000},
- {"APLL_CON1_L8", APLL_CON1_L8, 0x00000000},
- {"APLL_CON1_L7", APLL_CON1_L7, 0x00000000},
- {"APLL_CON1_L6", APLL_CON1_L6, 0x00000000},
- {"APLL_CON1_L5", APLL_CON1_L5, 0x00000000},
- {"APLL_CON1_L4", APLL_CON1_L4, 0x00000000},
- {"APLL_CON1_L3", APLL_CON1_L3, 0x00000000},
- {"APLL_CON1_L2", APLL_CON1_L2, 0x00000000},
- {"APLL_CON1_L1", APLL_CON1_L1, 0x00000000},
- {"CLKDIV_IEM_L8", CLKDIV_IEM_L8, 0x00000000},
- {"CLKDIV_IEM_L7", CLKDIV_IEM_L7, 0x00000000},
- {"CLKDIV_IEM_L6", CLKDIV_IEM_L6, 0x00000000},
- {"CLKDIV_IEM_L5", CLKDIV_IEM_L5, 0x00000000},
- {"CLKDIV_IEM_L4", CLKDIV_IEM_L4, 0x00000000},
- {"CLKDIV_IEM_L3", CLKDIV_IEM_L3, 0x00000000},
- {"CLKDIV_IEM_L2", CLKDIV_IEM_L2, 0x00000000},
- {"CLKDIV_IEM_L1", CLKDIV_IEM_L1, 0x00000000},
-};
-
-#define EXYNOS4210_CMU_REGS_MEM_SIZE 0x4000
-
-/*
- * for indexing register in the uint32_t array
- *
- * 'reg' - register offset (see offsets definitions above)
- *
- */
-#define I_(reg) (reg / sizeof(uint32_t))
-
-#define XOM_0 1 /* Select XXTI (0) or XUSBXTI (1) base clock source */
-
-/*
- * Offsets in CLK_SRC_CPU register
- * for control MUXMPLL and MUXAPLL
- *
- * 0 = FINPLL, 1 = MOUTM(A)PLLFOUT
- */
-#define MUX_APLL_SEL_SHIFT 0
-#define MUX_MPLL_SEL_SHIFT 8
-#define MUX_CORE_SEL_SHIFT 16
-#define MUX_HPM_SEL_SHIFT 20
-
-#define MUX_APLL_SEL (1 << MUX_APLL_SEL_SHIFT)
-#define MUX_MPLL_SEL (1 << MUX_MPLL_SEL_SHIFT)
-#define MUX_CORE_SEL (1 << MUX_CORE_SEL_SHIFT)
-#define MUX_HPM_SEL (1 << MUX_HPM_SEL_SHIFT)
-
-/* Offsets for fields in CLK_MUX_STAT_CPU register */
-#define APLL_SEL_SHIFT 0
-#define APLL_SEL_MASK 0x00000007
-#define MPLL_SEL_SHIFT 8
-#define MPLL_SEL_MASK 0x00000700
-#define CORE_SEL_SHIFT 16
-#define CORE_SEL_MASK 0x00070000
-#define HPM_SEL_SHIFT 20
-#define HPM_SEL_MASK 0x00700000
-
-
-/* Offsets for fields in <pll>_CON0 register */
-#define PLL_ENABLE_SHIFT 31
-#define PLL_ENABLE_MASK 0x80000000 /* [31] bit */
-#define PLL_LOCKED_MASK 0x20000000 /* [29] bit */
-#define PLL_MDIV_SHIFT 16
-#define PLL_MDIV_MASK 0x03FF0000 /* [25:16] bits */
-#define PLL_PDIV_SHIFT 8
-#define PLL_PDIV_MASK 0x00003F00 /* [13:8] bits */
-#define PLL_SDIV_SHIFT 0
-#define PLL_SDIV_MASK 0x00000007 /* [2:0] bits */
-
-/*
- * Offset in CLK_DIV_CPU0 register
- * for DIVAPLL clock divider ratio
- */
-#define APLL_RATIO_SHIFT 24
-#define APLL_RATIO_MASK 0x07000000 /* [26:24] bits */
-
-/*
- * Offset in CLK_DIV_TOP register
- * for DIVACLK_100 clock divider ratio
- */
-#define ACLK_100_RATIO_SHIFT 4
-#define ACLK_100_RATIO_MASK 0x000000f0 /* [7:4] bits */
-
-/* Offset in CLK_SRC_TOP0 register */
-#define MUX_ACLK_100_SEL_SHIFT 16
-
-/*
- * Offsets in CLK_SRC_PERIL0 register
- * for clock sources of UARTs
- */
-#define UART0_SEL_SHIFT 0
-#define UART1_SEL_SHIFT 4
-#define UART2_SEL_SHIFT 8
-#define UART3_SEL_SHIFT 12
-#define UART4_SEL_SHIFT 16
-/*
- * Offsets in CLK_DIV_PERIL0 register
- * for clock divider of UARTs
- */
-#define UART0_DIV_SHIFT 0
-#define UART1_DIV_SHIFT 4
-#define UART2_DIV_SHIFT 8
-#define UART3_DIV_SHIFT 12
-#define UART4_DIV_SHIFT 16
-
-#define SOURCES_NUMBER 9
-
-typedef struct ClockChangeEntry {
- QTAILQ_ENTRY(ClockChangeEntry) entry;
- ClockChangeHandler *func;
- void *opaque;
-} ClockChangeEntry;
-
-#define TYPE_EXYNOS4210_CMU "exynos4210.cmu"
-#define TYPE_EXYNOS4210_CLOCK "exynos4210.clock"
-
-typedef struct {
-
- const char *name;
- int32_t id;
- uint64_t rate;
-
- /* Current source clock */
- int32_t src_id;
- /*
- * Available sources. Their order must correspond to CLK_SRC_ register
- */
- int32_t src_ids[SOURCES_NUMBER];
-
- uint32_t src_reg; /* Offset of CLK_SRC_<*> register */
- uint32_t div_reg; /* Offset of CLK_DIV_<*> register */
-
- /*
- * Shift for MUX_<clk>_SEL value which is stored
- * in appropriate CLK_MUX_STAT_<cmu> register
- */
- uint8_t mux_shift;
-
- /*
- * Shift for <clk>_RATIO value which is stored
- * in appropriate CLK_DIV_<cmu> register
- */
- uint8_t div_shift;
-
- /* Which CMU controls this clock */
- int32_t cmu_id;
-
- QTAILQ_HEAD(, ClockChangeEntry) clock_change_handler;
-
-} Exynos4210ClockState;
-
-
-typedef struct {
-
- SysBusDevice busdev;
- MemoryRegion iomem;
-
- /* registers values */
- uint32_t reg[EXYNOS4210_CMU_REGS_MEM_SIZE / sizeof(uint32_t)];
-
- /* which CMU it is */
- Exynos4210Cmu cmu_id;
-
- /* registers information for debugging and resetting */
- Exynos4210CmuReg *regs;
- int regs_number;
-
- Exynos4210ClockState *clock;
- int clock_number; /* how many clocks are controlled by given CMU */
-
-} Exynos4210CmuState;
-
-
-/* Clocks from Clock Pads */
-/*
- * Two following clocks aren't controlled by any CMUs. These structures are
- * used directly from global space and their fields shouldn't be modified.
- */
-
-/* It should be used only for testing purposes. XOM_0 is 0 */
-static Exynos4210ClockState xxti = {
- .name = "XXTI",
- .id = EXYNOS4210_XXTI,
- .rate = 24000000,
- .cmu_id = UNSPECIFIED_CMU,
-};
-
-/* Main source. XOM_0 is 1 */
-static Exynos4210ClockState xusbxti = {
- .name = "XUSBXTI",
- .id = EXYNOS4210_XUSBXTI,
- .rate = 24000000,
- .cmu_id = UNSPECIFIED_CMU,
-};
-
-//static Exynos4210ClockState usb_phy = {
-// .name = "USB_PHY",
-// .id = EXYNOS4210_USB_PHY,
-// .src_id = EXYNOS4210_XUSBXTI,
-// .cmu_id = UNSPECIFIED_CMU,
-//};
-//
-//static Exynos4210ClockState usb_host_phy = {
-// .name = "USB_HOST_PHY",
-// .id = EXYNOS4210_USB_HOST_PHY,
-// .src_id = EXYNOS4210_XUSBXTI,
-// .cmu_id = UNSPECIFIED_CMU,
-//};
-//
-//static Exynos4210ClockState hdmi_phy = {
-// .name = "HDMI_PHY",
-// .id = EXYNOS4210_HDMI_PHY,
-// .src_id = EXYNOS4210_XUSBXTI,
-// .cmu_id = UNSPECIFIED_CMU,
-//};
-
-
-/* PLLs */
-
-static Exynos4210ClockState mpll = {
- .name = "MPLL",
- .id = EXYNOS4210_MPLL,
- .src_id = (XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI),
- .div_reg = PLL_CON0_(MPLL),
- .cmu_id = EXYNOS4210_CMU_CPU,
-};
-
-static Exynos4210ClockState apll = {
- .name = "APLL",
- .id = EXYNOS4210_APLL,
- .src_id = (XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI),
- .div_reg = PLL_CON0_(APLL),
- .cmu_id = EXYNOS4210_CMU_CPU,
-};
-
-
-/**/
-
-static Exynos4210ClockState sclk_hdmi24m = {
- .name = "SCLK_HDMI24M",
- .id = EXYNOS4210_SCLK_HDMI24M,
- .rate = 24000000,
-// .src_id = EXYNOS4210_HDMI_PHY,
- .cmu_id = UNSPECIFIED_CMU,
-};
-
-static Exynos4210ClockState sclk_usbphy0 = {
- .name = "SCLK_USBPHY0",
- .id = EXYNOS4210_SCLK_USBPHY0,
- .rate = 24000000,
-// .src_id = EXYNOS4210_USB_PHY,
- .cmu_id = UNSPECIFIED_CMU,
-};
-
-static Exynos4210ClockState sclk_usbphy1 = {
- .name = "SCLK_USBPHY1",
- .id = EXYNOS4210_SCLK_USBPHY1,
- .rate = 24000000,
-// .src_id = EXYNOS4210_USB_HOST_PHY,
- .cmu_id = UNSPECIFIED_CMU,
-};
-
-static Exynos4210ClockState sclk_hdmiphy = {
- .name = "SCLK_HDMIPHY",
- .id = EXYNOS4210_SCLK_HDMIPHY,
- .rate = 24000000,
-// .src_id = EXYNOS4210_HDMI_PHY,
- .cmu_id = UNSPECIFIED_CMU,
-};
-
-static Exynos4210ClockState sclk_mpll = {
- .name = "SCLK_MPLL",
- .id = EXYNOS4210_SCLK_MPLL,
- .src_ids = {XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI,
- EXYNOS4210_MPLL},
- .src_reg = CLK_SRC_(CPU_BLK),
- .mux_shift = MUX_MPLL_SEL_SHIFT,
- .cmu_id = EXYNOS4210_CMU_CPU,
-};
-
-static Exynos4210ClockState sclk_apll = {
- .name = "SCLK_APLL",
- .id = EXYNOS4210_SCLK_APLL,
- .src_ids = {XOM_0 ? EXYNOS4210_XUSBXTI : EXYNOS4210_XXTI,
- EXYNOS4210_APLL},
- .src_reg = CLK_SRC_(CPU_BLK),
- .div_reg = CLK_DIV_(CPU0_BLK),
- .mux_shift = MUX_APLL_SEL_SHIFT,
- .div_shift = APLL_RATIO_SHIFT,
- .cmu_id = EXYNOS4210_CMU_CPU,
-};
-
-static Exynos4210ClockState aclk_100 = {
- .name = "ACLK_100",
- .id = EXYNOS4210_ACLK_100,
- .src_ids = {EXYNOS4210_SCLK_MPLL, EXYNOS4210_SCLK_APLL},
- .src_reg = CLK_SRC_(TOP0_BLK),
- .div_reg = CLK_DIV_(TOP_BLK),
- .mux_shift = MUX_ACLK_100_SEL_SHIFT,
- .div_shift = ACLK_100_RATIO_SHIFT,
- .cmu_id = EXYNOS4210_CMU_TOP,
-};
-
-static Exynos4210ClockState sclk_uart0 = {
- .name = "SCLK_UART0",
- .id = EXYNOS4210_SCLK_UART0,
- .src_ids = {EXYNOS4210_XXTI,
- EXYNOS4210_XUSBXTI,
- EXYNOS4210_SCLK_HDMI24M,
- EXYNOS4210_SCLK_USBPHY0,
- EXYNOS4210_SCLK_USBPHY1,
- EXYNOS4210_SCLK_HDMIPHY,
- EXYNOS4210_SCLK_MPLL},
- .src_reg = CLK_SRC_(PERIL0_BLK),
- .div_reg = CLK_DIV_(PERIL0_BLK),
- .mux_shift = UART0_SEL_SHIFT,
- .div_shift = UART0_DIV_SHIFT,
- .cmu_id = EXYNOS4210_CMU_TOP,
-};
-
-static Exynos4210ClockState sclk_uart1 = {
- .name = "SCLK_UART1",
- .id = EXYNOS4210_SCLK_UART1,
- .src_ids = {EXYNOS4210_XXTI,
- EXYNOS4210_XUSBXTI,
- EXYNOS4210_SCLK_HDMI24M,
- EXYNOS4210_SCLK_USBPHY0,
- EXYNOS4210_SCLK_USBPHY1,
- EXYNOS4210_SCLK_HDMIPHY,
- EXYNOS4210_SCLK_MPLL},
- .src_reg = CLK_SRC_(PERIL0_BLK),
- .div_reg = CLK_DIV_(PERIL0_BLK),
- .mux_shift = UART1_SEL_SHIFT,
- .div_shift = UART1_DIV_SHIFT,
- .cmu_id = EXYNOS4210_CMU_TOP,
-};
-
-static Exynos4210ClockState sclk_uart2 = {
- .name = "SCLK_UART2",
- .id = EXYNOS4210_SCLK_UART2,
- .src_ids = {EXYNOS4210_XXTI,
- EXYNOS4210_XUSBXTI,
- EXYNOS4210_SCLK_HDMI24M,
- EXYNOS4210_SCLK_USBPHY0,
- EXYNOS4210_SCLK_USBPHY1,
- EXYNOS4210_SCLK_HDMIPHY,
- EXYNOS4210_SCLK_MPLL},
- .src_reg = CLK_SRC_(PERIL0_BLK),
- .div_reg = CLK_DIV_(PERIL0_BLK),
- .mux_shift = UART2_SEL_SHIFT,
- .div_shift = UART2_DIV_SHIFT,
- .cmu_id = EXYNOS4210_CMU_TOP,
-};
-
-static Exynos4210ClockState sclk_uart3 = {
- .name = "SCLK_UART3",
- .id = EXYNOS4210_SCLK_UART3,
- .src_ids = {EXYNOS4210_XXTI,
- EXYNOS4210_XUSBXTI,
- EXYNOS4210_SCLK_HDMI24M,
- EXYNOS4210_SCLK_USBPHY0,
- EXYNOS4210_SCLK_USBPHY1,
- EXYNOS4210_SCLK_HDMIPHY,
- EXYNOS4210_SCLK_MPLL},
- .src_reg = CLK_SRC_(PERIL0_BLK),
- .div_reg = CLK_DIV_(PERIL0_BLK),
- .mux_shift = UART3_SEL_SHIFT,
- .div_shift = UART3_DIV_SHIFT,
- .cmu_id = EXYNOS4210_CMU_TOP,
-};
-
-static Exynos4210ClockState sclk_uart4 = {
- .name = "SCLK_UART4",
- .id = EXYNOS4210_SCLK_UART4,
- .src_ids = {EXYNOS4210_XXTI,
- EXYNOS4210_XUSBXTI,
- EXYNOS4210_SCLK_HDMI24M,
- EXYNOS4210_SCLK_USBPHY0,
- EXYNOS4210_SCLK_USBPHY1,
- EXYNOS4210_SCLK_HDMIPHY,
- EXYNOS4210_SCLK_MPLL},
- .src_reg = CLK_SRC_(PERIL0_BLK),
- .div_reg = CLK_DIV_(PERIL0_BLK),
- .mux_shift = UART4_SEL_SHIFT,
- .div_shift = UART4_DIV_SHIFT,
- .cmu_id = EXYNOS4210_CMU_TOP,
-};
-
-/*
- * This array must correspond to Exynos4210Clock enumerator
- * which is defined in exynos4210.h file
- *
- */
-static Exynos4210ClockState *exynos4210_clock[] = {
- NULL,
- &xxti,
- &xusbxti,
-// &usb_phy,
-// &usb_host_phy,
-// &hdmi_phy,
- &apll,
- &mpll,
- &sclk_hdmi24m,
- &sclk_usbphy0,
- &sclk_usbphy1,
- &sclk_hdmiphy,
- &sclk_apll,
- &sclk_mpll,
- &aclk_100,
- &sclk_uart0,
- &sclk_uart1,
- &sclk_uart2,
- &sclk_uart3,
- &sclk_uart4,
- NULL,
-};
-
-/*
- * This array must correspond to Exynos4210Cmu enumerator
- * which is defined in exynos4210.h file
- *
- */
-static char exynos4210_cmu_path[][13] = {
- "cmu_leftbus",
- "cmu_rightbus",
- "cmu_top",
- "cmu_dmc",
- "cmu_cpu",
-};
-
-#if DEBUG_CMU_EXTEND
-/* The only meaning of life - debugging. This function should be only used
- * inside PRINT_DEBUG_EXTEND macros
- */
-static const char *exynos4210_cmu_regname(Exynos4210CmuState *s,
- target_phys_addr_t offset)
-{
- int i;
-
- for (i = 0; i < s->regs_number; i++) {
- if (offset == s->regs[i].offset) {
- return s->regs[i].name;
- }
- }
-
- return NULL;
-}
-#endif
-
-
-static Exynos4210ClockState *exynos4210_clock_find(Exynos4210Clock clock_id)
-{
- int i;
- int cmu_id;
- Object *cmu;
- Exynos4210CmuState *s;
-
- cmu_id = exynos4210_clock[clock_id]->cmu_id;
-
- if (cmu_id == UNSPECIFIED_CMU) {
- for (i = 1; i < EXYNOS4210_CLOCKS_NUMBER; i++) {
- if (exynos4210_clock[i]->id == clock_id) {
-
- PRINT_DEBUG("Clock %s [%p] in CMU %d have been found\n",
- exynos4210_clock[i]->name,
- exynos4210_clock[i],
- cmu_id);
-
- return exynos4210_clock[i];
- }
- }
- }
-
- cmu = object_resolve_path(exynos4210_cmu_path[cmu_id], NULL);
- s = OBJECT_CHECK(Exynos4210CmuState, cmu, TYPE_EXYNOS4210_CMU);
-
- for (i = 0; i < s->clock_number; i++) {
- if (s->clock[i].id == clock_id) {
-
- PRINT_DEBUG("Clock %s [%p] in CMU %d have been found\n",
- s->clock[i].name,
- &s->clock[i],
- s->clock[i].cmu_id);
- return &s->clock[i];
- }
- }
-
- PRINT_ERROR("Clock %d not found\n", clock_id);
-
- return NULL;
-}
-
-
-void exynos4210_register_clock_handler(ClockChangeHandler *func,
- Exynos4210Clock clock_id, void *opaque)
-{
- ClockChangeEntry *cce = g_malloc0(sizeof(ClockChangeEntry));
- Exynos4210ClockState *clock = exynos4210_clock_find(clock_id);
-
- if (clock == NULL) {
- hw_error("We aren't be able to find clock %d\n", clock_id);
- } else if (clock->cmu_id == UNSPECIFIED_CMU) {
-
- PRINT_DEBUG("Clock %s never are changed. Handler won't be set.",
- exynos4210_clock[clock_id]->name);
-
- return;
- }
-
- cce->func = func;
- cce->opaque = opaque;
-
- QTAILQ_INSERT_TAIL(&clock->clock_change_handler, cce, entry);
-
- PRINT_DEBUG("For %s have been set handler [%p]\n", clock->name, cce->func);
-
- return;
-}
-
-uint64_t exynos4210_cmu_get_rate(Exynos4210Clock clock_id)
-{
- Exynos4210ClockState *clock = exynos4210_clock_find(clock_id);
-
- if (clock == NULL) {
- hw_error("We aren't be able to find clock %d\n", clock_id);
- }
-
- return clock->rate;
-}
-
-static void exynos4210_cmu_set_pll(void *opaque, Exynos4210ClockState *pll)
-{
- Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
- Exynos4210ClockState *source;
- target_phys_addr_t offset = pll->div_reg;
- ClockChangeEntry *cce;
- uint32_t pdiv, mdiv, sdiv, enable;
-
- source = exynos4210_clock_find(pll->src_id);
-
- if (source == NULL) {
- hw_error("We haven't find source clock %d (requested for %s)\n",
- pll->src_id, pll->name);
- }
-
- /*
- * FOUT = MDIV * FIN / (PDIV * 2^(SDIV-1))
- */
-
- enable = (s->reg[I_(offset)] & PLL_ENABLE_MASK) >> PLL_ENABLE_SHIFT;
- mdiv = (s->reg[I_(offset)] & PLL_MDIV_MASK) >> PLL_MDIV_SHIFT;
- pdiv = (s->reg[I_(offset)] & PLL_PDIV_MASK) >> PLL_PDIV_SHIFT;
- sdiv = (s->reg[I_(offset)] & PLL_SDIV_MASK) >> PLL_SDIV_SHIFT;
-
- if (source) {
- if (enable) {
- pll->rate = mdiv * source->rate / (pdiv * (1 << (sdiv-1)));
- } else {
- pll->rate = 0;
- }
- } else {
- hw_error("%s: Source undefined for %s\n", __FUNCTION__, pll->name);
- }
-
- QTAILQ_FOREACH(cce, &pll->clock_change_handler, entry) {
- cce->func(cce->opaque);
- }
-
- PRINT_DEBUG("%s rate: %llu\n", pll->name, pll->rate);
-
- s->reg[I_(offset)] |= PLL_LOCKED_MASK;
-}
-
-
-static void exynos4210_cmu_set_rate(void *opaque, Exynos4210Clock clock_id)
-{
- Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
- Exynos4210ClockState *clock = exynos4210_clock_find(clock_id);
- ClockChangeEntry *cce;
-
- if (clock == NULL) {
- hw_error("We haven't find source clock %d ", clock_id);
- }
-
- if ((clock->id == EXYNOS4210_MPLL) || (clock->id == EXYNOS4210_APLL)) {
-
- exynos4210_cmu_set_pll(s, clock);
-
- } else if ((clock->cmu_id != UNSPECIFIED_CMU)) {
-
- Exynos4210ClockState *source;
-
- uint32_t src_index = I_(clock->src_reg);
- uint32_t div_index = I_(clock->div_reg);
-
- clock->src_id = clock->src_ids[(s->reg[src_index] >>
- clock->mux_shift) & 0xf];
-
- source = exynos4210_clock_find(clock->src_id);
- if (source == NULL) {
- hw_error("We haven't find source clock %d (requested for %s)\n",
- clock->src_id, clock->name);
- }
-
- clock->rate = muldiv64(source->rate, 1,
- ((((clock->div_reg ? s->reg[div_index] : 0) >>
- clock->div_shift) & 0xf) + 1));
-
- QTAILQ_FOREACH(cce, &clock->clock_change_handler, entry) {
- cce->func(cce->opaque);
- }
-
- PRINT_DEBUG_EXTEND("SRC: <0x%05x> %s, SHIFT: %d\n",
- clock->src_reg,
- exynos4210_cmu_regname(s, clock->src_reg),
- clock->mux_shift);
-
- PRINT_DEBUG("%s [%s:%llu]: %llu\n",
- clock->name,
- source->name,
- (long long unsigned int)source->rate,
- (long long unsigned int)clock->rate);
- }
-}
-
-
-static uint64_t exynos4210_cmu_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
-
- if (offset > (EXYNOS4210_CMU_REGS_MEM_SIZE - sizeof(uint32_t))) {
- PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
- return 0;
- }
-
- if (offset & EXTENDED_REGION_MASK) {
- if (s->cmu_id == EXYNOS4210_CMU_DMC) {
- switch (offset & 0xFFF) {
- case DCGIDX_MAP0:
- case DCGIDX_MAP1:
- case DCGIDX_MAP2:
- case DCGPERF_MAP0:
- case DCGPERF_MAP1:
- case DVCIDX_MAP:
- case FREQ_CPU:
- case FREQ_DPM:
- case DVSEMCLK_EN:
- case MAXPERF:
- return s->reg[I_(offset)];
- default:
- PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
- return 0;
- }
- }
-
- if (s->cmu_id == EXYNOS4210_CMU_CPU) {
- switch (offset & 0xFFF) {
- case ARMCLK_STOPCTRL:
- case ATCLK_STOPCTRL:
- case PARITYFAIL_STATUS:
- case PARITYFAIL_CLEAR:
- case PWR_CTRL:
- case APLL_CON0_L8:
- case APLL_CON0_L7:
- case APLL_CON0_L6:
- case APLL_CON0_L5:
- case APLL_CON0_L4:
- case APLL_CON0_L3:
- case APLL_CON0_L2:
- case APLL_CON0_L1:
- case IEM_CONTROL:
- case APLL_CON1_L8:
- case APLL_CON1_L7:
- case APLL_CON1_L6:
- case APLL_CON1_L5:
- case APLL_CON1_L4:
- case APLL_CON1_L3:
- case APLL_CON1_L2:
- case APLL_CON1_L1:
- case CLKDIV_IEM_L8:
- case CLKDIV_IEM_L7:
- case CLKDIV_IEM_L6:
- case CLKDIV_IEM_L5:
- case CLKDIV_IEM_L4:
- case CLKDIV_IEM_L3:
- case CLKDIV_IEM_L2:
- case CLKDIV_IEM_L1:
- return s->reg[I_(offset)];
- default:
- PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
- return 0;
- }
- }
- }
-
- switch (offset & GROUP_MASK) {
- case PLL_LOCK:
- case PLL_CON:
- case CLK_SRC:
- case CLK_SRC_MASK:
- case CLK_MUX_STAT:
- case CLK_DIV:
- case CLK_DIV_STAT:
- case 0x700: /* Reserved */
- case CLK_GATE_SCLK: /* reserved? */
- case CLK_GATE_IP:
- case CLKOUT_CMU:
- return s->reg[I_(offset)];
- default:
- PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
- return 0;
- }
-
- PRINT_DEBUG_EXTEND("<0x%05x> %s -> %08x\n", offset,
- exynos4210_cmu_regname(s, offset), s->reg[I_(offset)]);
-}
-
-
-static void exynos4210_cmu_write(void *opaque, target_phys_addr_t offset,
- uint64_t val, unsigned size)
-{
- Exynos4210CmuState *s = (Exynos4210CmuState *)opaque;
- uint32_t group, block;
-
- group = offset & GROUP_MASK;
- block = offset & BLOCK_MASK;
-
- switch (group) {
- case PLL_LOCK:
- /* it's not necessary at this moment
- * TODO: do it
- */
- break;
- case PLL_CON:
- switch (block) {
- case APLL:
- {
- uint32_t pre_val = s->reg[I_(offset)];
- s->reg[I_(offset)] = val;
- val = (val & ~PLL_LOCKED_MASK) | (pre_val & PLL_LOCKED_MASK);
- s->reg[I_(offset)] = val;
- exynos4210_cmu_set_rate(s, EXYNOS4210_APLL);
- }
- break;
- case MPLL:
- {
- uint32_t pre_val = s->reg[I_(offset)];
- s->reg[I_(offset)] = val;
- val = (val & ~PLL_LOCKED_MASK) | (pre_val & PLL_LOCKED_MASK);
- s->reg[I_(offset)] = val;
- exynos4210_cmu_set_rate(s, EXYNOS4210_MPLL);
- }
- break;
- }
- break;
- case CLK_SRC:
- switch (block) {
- case CPU_BLK:
- {
- uint32_t pre_val = s->reg[I_(offset)];
- s->reg[I_(offset)] = val;
-
- if (val & MUX_APLL_SEL) {
- s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
- (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] & ~(APLL_SEL_MASK)) |
- (2 << APLL_SEL_SHIFT);
-
- if ((pre_val & MUX_APLL_SEL) !=
- (s->reg[I_(offset)] & MUX_APLL_SEL)) {
- exynos4210_cmu_set_rate(s, EXYNOS4210_APLL);
- }
-
- } else {
- s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
- (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] & ~(APLL_SEL_MASK)) |
- (1 << APLL_SEL_SHIFT);
-
- if ((pre_val & MUX_APLL_SEL) !=
- (s->reg[I_(offset)] & MUX_APLL_SEL)) {
- exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_XUSBXTI :
- EXYNOS4210_XXTI);
- }
- }
-
-
- if (val & MUX_MPLL_SEL) {
- s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
- (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] & ~(MPLL_SEL_MASK)) |
- (2 << MPLL_SEL_SHIFT);
-
- if ((pre_val & MUX_MPLL_SEL) !=
- (s->reg[I_(offset)] & MUX_MPLL_SEL)) {
- exynos4210_cmu_set_rate(s, EXYNOS4210_MPLL);
- }
-
- } else {
- s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
- (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] & ~(MPLL_SEL_MASK)) |
- (1 << MPLL_SEL_SHIFT);
-
- if ((pre_val & MUX_MPLL_SEL) !=
- (s->reg[I_(offset)] & MUX_MPLL_SEL)) {
- exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_XUSBXTI :
- EXYNOS4210_XXTI);
- }
- }
-
- if (val & MUX_CORE_SEL) {
- s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
- (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] & ~(CORE_SEL_MASK)) |
- (2 << CORE_SEL_SHIFT);
-
- if ((pre_val & MUX_CORE_SEL) !=
- (s->reg[I_(offset)] & MUX_CORE_SEL)) {
- exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPLL);
- }
-
- } else {
- s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
- (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] & ~(CORE_SEL_MASK)) |
- (1 << CORE_SEL_SHIFT);
-
- if ((pre_val & MUX_CORE_SEL) !=
- (s->reg[I_(offset)] & MUX_CORE_SEL)) {
- exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_XUSBXTI :
- EXYNOS4210_XXTI);
- }
- }
-
- if (val & MUX_HPM_SEL) {
- exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPLL);
- s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
- (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] & ~(HPM_SEL_MASK)) |
- (2 << HPM_SEL_SHIFT);
-
- if ((pre_val & MUX_HPM_SEL) !=
- (s->reg[I_(offset)] & MUX_HPM_SEL)) {
- exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPLL);
- }
-
- } else {
- s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] =
- (s->reg[I_(CLK_MUX_STAT_(CPU_BLK))] & ~(HPM_SEL_MASK)) |
- (1 << HPM_SEL_SHIFT);
-
- if ((pre_val & MUX_HPM_SEL) !=
- (s->reg[I_(offset)] & MUX_HPM_SEL)) {
- exynos4210_cmu_set_rate(s, XOM_0 ? EXYNOS4210_XUSBXTI :
- EXYNOS4210_XXTI);
- }
- }
- }
- break;
- case TOP0_BLK:
- s->reg[I_(offset)] = val;
- exynos4210_cmu_set_rate(s, EXYNOS4210_ACLK_100);
- break;
- default:
- PRINT_ERROR("Unknown functional block: 0x%x\n", (int)block);
- }
- break;
- case CLK_SRC_MASK:
- break;
- case CLK_MUX_STAT:
- break;
- case CLK_DIV:
- switch (block) {
- case TOP_BLK:
- s->reg[I_(offset)] = val;
- exynos4210_cmu_set_rate(s, EXYNOS4210_ACLK_100);
- break;
- case CPU0_BLK:
- s->reg[I_(offset)] = val;
- exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_APLL);
- exynos4210_cmu_set_rate(s, EXYNOS4210_SCLK_MPLL);
- break;
- }
- case CLK_DIV_STAT: /* CLK_DIV_STAT */
- case 0x700: /* Reserved */
- case CLK_GATE_SCLK: /* reserved? */
- case CLK_GATE_IP:
- case CLKOUT_CMU:
- break;
- default:
- PRINT_ERROR("Bad offset: 0x%x\n", (int)offset);
- }
-}
-
-static const MemoryRegionOps exynos4210_cmu_ops = {
- .read = exynos4210_cmu_read,
- .write = exynos4210_cmu_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static void clock_rate_changed(void *opaque)
-{
- Exynos4210ClockState *cs = (Exynos4210ClockState *)opaque;
- Object *cmu = object_resolve_path(exynos4210_cmu_path[cs->cmu_id], NULL);
- Exynos4210CmuState *s = OBJECT_CHECK(Exynos4210CmuState, cmu,
- TYPE_EXYNOS4210_CMU);
-
- PRINT_DEBUG("Clock %s was changed\n", cs->name);
-
- exynos4210_cmu_set_rate(s, cs->id);
-
-}
-
-static void exynos4210_cmu_reset(DeviceState *dev)
-{
- Exynos4210CmuState *s = OBJECT_CHECK(Exynos4210CmuState, OBJECT(dev),
- TYPE_EXYNOS4210_CMU);
- int i, j;
- uint32_t index = 0;
-
- for (i = 0; i < s->regs_number; i++) {
- index = (s->regs[i].offset) / sizeof(uint32_t);
- s->reg[index] = s->regs[i].reset_value;
- }
-
- for (i = 0; i < s->clock_number; i++) {
-
- for (j = 0; j < SOURCES_NUMBER; j++) {
-
- if (s->clock[i].src_ids[j] == UNSPECIFIED_CLOCK) {
-
- if (j == 0) {
- /*
- * we have empty '.sources[]' array
- */
- if (s->clock[i].src_id != UNSPECIFIED_CLOCK) {
-
- s->clock[i].src_ids[j] = s->clock[i].src_id;
-
- } else {
-
- if (s->clock[i].cmu_id != UNSPECIFIED_CMU) {
- /*
- * We haven't any defined sources for this clock.
- * Error during definition of appropriate clock
- * structure
- */
- hw_error("exynos4210_cmu_reset:"
- "There aren't any sources for %s clock!\n",
- s->clock[i].name);
- } else {
- /*
- * we don't need any sources for this clock
- * because it's a root clock
- */
- break;
- }
- }
- } else {
- break; /* leave because there are no more sources */
- }
- } /* src_ids[j] == UNSPECIFIED_CLOCK */
-
- Exynos4210ClockState *source =
- exynos4210_clock_find(s->clock[i].src_ids[j]);
-
- if (source == NULL) {
- hw_error("We aren't be able to find source clock %d "
- "(requested for %s)\n",
- s->clock[i].src_ids[j], s->clock[i].name);
- }
-
- if (source->cmu_id != UNSPECIFIED_CMU) {
-
- exynos4210_register_clock_handler(clock_rate_changed,
- s->clock[i].src_ids[j], &s->clock[i]);
- }
- } /* SOURCES_NUMBER */
-
- exynos4210_cmu_set_rate(s, s->clock[i].id);
- }
-
- PRINT_DEBUG("CMU %d reset completed\n", s->cmu_id);
-}
-
-static const VMStateDescription vmstate_exynos4210_clock = {
- .name = TYPE_EXYNOS4210_CLOCK,
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT64(rate, Exynos4210ClockState),
- VMSTATE_INT32(src_id, Exynos4210ClockState),
- VMSTATE_INT32_ARRAY(src_ids, Exynos4210ClockState, SOURCES_NUMBER),
- VMSTATE_UINT32(src_reg, Exynos4210ClockState),
- VMSTATE_UINT32(div_reg, Exynos4210ClockState),
- VMSTATE_UINT8(mux_shift, Exynos4210ClockState),
- VMSTATE_UINT8(div_shift, Exynos4210ClockState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_exynos4210_cmu = {
- .name = TYPE_EXYNOS4210_CMU,
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(reg, Exynos4210CmuState,
- EXYNOS4210_CMU_REGS_MEM_SIZE / sizeof(uint32_t)),
- VMSTATE_STRUCT_VARRAY_INT32(clock, Exynos4210CmuState,
- clock_number, 0,
- vmstate_exynos4210_clock,
- Exynos4210ClockState),
- VMSTATE_END_OF_LIST()
- }
-};
-
-DeviceState *exynos4210_cmu_create(target_phys_addr_t addr,
- Exynos4210Cmu cmu_id)
-{
- DeviceState *dev;
- SysBusDevice *bus;
-
- dev = qdev_create(NULL, TYPE_EXYNOS4210_CMU);
-
- qdev_prop_set_int32(dev, "cmu_id", cmu_id);
-
- bus = sysbus_from_qdev(dev);
- qdev_init_nofail(dev);
- if (addr != (target_phys_addr_t)-1) {
- sysbus_mmio_map(bus, 0, addr);
- }
-
- return dev;
-}
-
-static int exynos4210_cmu_init(SysBusDevice *dev)
-{
- Exynos4210CmuState *s = FROM_SYSBUS(Exynos4210CmuState, dev);
- int i, n;
-
- memory_region_init_io(&s->iomem, &exynos4210_cmu_ops, s,
- TYPE_EXYNOS4210_CMU, EXYNOS4210_CMU_REGS_MEM_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-
- switch (s->cmu_id) {
- case EXYNOS4210_CMU_LEFTBUS:
- s->regs = exynos4210_cmu_leftbus_regs;
- s->regs_number = ARRAY_SIZE(exynos4210_cmu_leftbus_regs);
- break;
- case EXYNOS4210_CMU_RIGHTBUS:
- s->regs = exynos4210_cmu_rightbus_regs;
- s->regs_number = ARRAY_SIZE(exynos4210_cmu_rightbus_regs);
- break;
- case EXYNOS4210_CMU_TOP:
- s->regs = exynos4210_cmu_top_regs;
- s->regs_number = ARRAY_SIZE(exynos4210_cmu_top_regs);
- break;
- case EXYNOS4210_CMU_DMC:
- s->regs = exynos4210_cmu_dmc_regs;
- s->regs_number = ARRAY_SIZE(exynos4210_cmu_dmc_regs);
- break;
- case EXYNOS4210_CMU_CPU:
- s->regs = exynos4210_cmu_cpu_regs;
- s->regs_number = ARRAY_SIZE(exynos4210_cmu_cpu_regs);
- break;
- default:
- hw_error("Wrong CMU: %d\n", s->cmu_id);
- }
-
- for (i = 1, n = 0; i < EXYNOS4210_CLOCKS_NUMBER; i++) {
- if (s->cmu_id == exynos4210_clock[i]->cmu_id) {
- n++;
- }
- }
-
- s->clock =
- (Exynos4210ClockState *)g_malloc0(n * sizeof(Exynos4210ClockState));
-
- for (i = 1, s->clock_number = 0; i < EXYNOS4210_CLOCKS_NUMBER; i++) {
-
- if (s->cmu_id == exynos4210_clock[i]->cmu_id) {
-
- memcpy(&s->clock[s->clock_number], exynos4210_clock[i],
- sizeof(Exynos4210ClockState));
-
- QTAILQ_INIT(&s->clock[s->clock_number].clock_change_handler);
-
- PRINT_DEBUG("Clock %s was added to \"%s\"\n",
- s->clock[s->clock_number].name,
- exynos4210_cmu_path[s->cmu_id]);
-
- s->clock_number++;
- }
- }
-
- object_property_add_child(object_get_root(), exynos4210_cmu_path[s->cmu_id],
- OBJECT(dev), NULL);
-
- return 0;
-}
-
-static Property exynos4210_cmu_properties[] = {
- DEFINE_PROP_INT32("cmu_id", Exynos4210CmuState, cmu_id, UNSPECIFIED_CMU),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_cmu_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_cmu_init;
- dc->reset = exynos4210_cmu_reset;
- dc->props = exynos4210_cmu_properties;
- dc->vmsd = &vmstate_exynos4210_cmu;
-}
-
-static TypeInfo exynos4210_cmu_info = {
- .name = TYPE_EXYNOS4210_CMU,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210CmuState),
- .class_init = exynos4210_cmu_class_init,
-};
-
-static void exynos4210_cmu_register_types(void)
-{
- type_register_static(&exynos4210_cmu_info);
-}
-
-type_init(exynos4210_cmu_register_types)
+++ /dev/null
-/*
- * Samsung exynos4210 Display Controller (FIMD)
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- * Based on LCD controller for Samsung S5PC1xx-based board emulation
- * by Kirill Batuzov <batuzovk@ispras.ru>
- *
- * Contributed by Mitsyanko Igor <i.mitsyanko@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu-common.h"
-#include "cpu-all.h"
-#include "sysbus.h"
-#include "console.h"
-#include "pixel_ops.h"
-#include "bswap.h"
-#include "../tizen/src/hw/maru_brightness.h"
-
-/* Debug messages configuration */
-#define EXYNOS4210_FIMD_DEBUG 0
-#define EXYNOS4210_FIMD_MODE_TRACE 0
-
-#if EXYNOS4210_FIMD_DEBUG == 0
- #define DPRINT_L1(fmt, args...) do { } while (0)
- #define DPRINT_L2(fmt, args...) do { } while (0)
- #define DPRINT_ERROR(fmt, args...) do { } while (0)
-#elif EXYNOS4210_FIMD_DEBUG == 1
- #define DPRINT_L1(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
- #define DPRINT_L2(fmt, args...) do { } while (0)
- #define DPRINT_ERROR(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
-#else
- #define DPRINT_L1(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
- #define DPRINT_L2(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
- #define DPRINT_ERROR(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
-#endif
-
-#if EXYNOS4210_FIMD_MODE_TRACE == 0
- #define DPRINT_TRACE(fmt, args...) do { } while (0)
-#else
- #define DPRINT_TRACE(fmt, args...) \
- do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
-#endif
-
-#define NUM_OF_WINDOWS 5
-#define FIMD_REGS_SIZE 0x4114
-
-/* Video main control registers */
-#define FIMD_VIDCON0 0x0000
-#define FIMD_VIDCON1 0x0004
-#define FIMD_VIDCON2 0x0008
-#define FIMD_VIDCON3 0x000C
-#define FIMD_VIDCON0_ENVID_F (1 << 0)
-#define FIMD_VIDCON0_ENVID (1 << 1)
-#define FIMD_VIDCON0_ENVID_MASK ((1 << 0) | (1 << 1))
-#define FIMD_VIDCON1_ROMASK 0x07FFE000
-
-/* Video time control registers */
-#define FIMD_VIDTCON_START 0x10
-#define FIMD_VIDTCON_END 0x1C
-#define FIMD_VIDTCON2_SIZE_MASK 0x07FF
-#define FIMD_VIDTCON2_HOR_SHIFT 0
-#define FIMD_VIDTCON2_VER_SHIFT 11
-
-/* Window control registers */
-#define FIMD_WINCON_START 0x0020
-#define FIMD_WINCON_END 0x0030
-#define FIMD_WINCON_ROMASK 0x82200000
-#define FIMD_WINCON_ENWIN (1 << 0)
-#define FIMD_WINCON_BLD_PIX (1 << 6)
-#define FIMD_WINCON_ALPHA_MUL (1 << 7)
-#define FIMD_WINCON_ALPHA_SEL (1 << 1)
-#define FIMD_WINCON_SWAP 0x078000
-#define FIMD_WINCON_SWAP_SHIFT 15
-#define FIMD_WINCON_SWAP_WORD 0x1
-#define FIMD_WINCON_SWAP_HWORD 0x2
-#define FIMD_WINCON_SWAP_BYTE 0x4
-#define FIMD_WINCON_SWAP_BITS 0x8
-#define FIMD_WINCON_BUFSTAT_L (1 << 21)
-#define FIMD_WINCON_BUFSTAT_H (1 << 31)
-#define FIMD_WINCON_BUFSTATUS ((1 << 21) | (1 << 31))
-#define FIMD_WINCON_BUF0_STAT ((0 << 21) | (0 << 31))
-#define FIMD_WINCON_BUF1_STAT ((1 << 21) | (0 << 31))
-#define FIMD_WINCON_BUF2_STAT ((0 << 21) | (1 << 31))
-#define FIMD_WINCON_BUFSELECT ((1 << 20) | (1 << 30))
-#define FIMD_WINCON_BUF0_SEL ((0 << 20) | (0 << 30))
-#define FIMD_WINCON_BUF1_SEL ((1 << 20) | (0 << 30))
-#define FIMD_WINCON_BUF2_SEL ((0 << 20) | (1 << 30))
-#define FIMD_WINCON_BUFMODE (1 << 14)
-#define IS_PALETTIZED_MODE(w) (w->wincon & 0xC)
-#define PAL_MODE_WITH_ALPHA(x) ((x) == 7)
-#define WIN_BPP_MODE(w) ((w->wincon >> 2) & 0xF)
-#define WIN_BPP_MODE_WITH_ALPHA(w) \
- (WIN_BPP_MODE(w) == 0xD || WIN_BPP_MODE(w) == 0xE)
-
-/* Shadow control register */
-#define FIMD_SHADOWCON 0x0034
-#define FIMD_WINDOW_PROTECTED(s, w) ((s) & (1 << (10 + (w))))
-/* Channel mapping control register */
-#define FIMD_WINCHMAP 0x003C
-
-/* Window position control registers */
-#define FIMD_VIDOSD_START 0x0040
-#define FIMD_VIDOSD_END 0x0088
-#define FIMD_VIDOSD_COORD_MASK 0x07FF
-#define FIMD_VIDOSD_HOR_SHIFT 11
-#define FIMD_VIDOSD_VER_SHIFT 0
-#define FIMD_VIDOSD_ALPHA_AEN0 0xFFF000
-#define FIMD_VIDOSD_AEN0_SHIFT 12
-#define FIMD_VIDOSD_ALPHA_AEN1 0x000FFF
-
-/* Frame buffer address registers */
-#define FIMD_VIDWADD0_START 0x00A0
-#define FIMD_VIDWADD0_END 0x00C4
-#define FIMD_VIDWADD0_END 0x00C4
-#define FIMD_VIDWADD1_START 0x00D0
-#define FIMD_VIDWADD1_END 0x00F4
-#define FIMD_VIDWADD2_START 0x0100
-#define FIMD_VIDWADD2_END 0x0110
-#define FIMD_VIDWADD2_PAGEWIDTH 0x1FFF
-#define FIMD_VIDWADD2_OFFSIZE 0x1FFF
-#define FIMD_VIDWADD2_OFFSIZE_SHIFT 13
-#define FIMD_VIDW0ADD0_B2 0x20A0
-#define FIMD_VIDW4ADD0_B2 0x20C0
-
-/* Video interrupt control registers */
-#define FIMD_VIDINTCON0 0x130
-#define FIMD_VIDINTCON1 0x134
-
-/* Window color key registers */
-#define FIMD_WKEYCON_START 0x140
-#define FIMD_WKEYCON_END 0x15C
-#define FIMD_WKEYCON0_COMPKEY 0x00FFFFFF
-#define FIMD_WKEYCON0_CTL_SHIFT 24
-#define FIMD_WKEYCON0_DIRCON (1 << 24)
-#define FIMD_WKEYCON0_KEYEN (1 << 25)
-#define FIMD_WKEYCON0_KEYBLEN (1 << 26)
-/* Window color key alpha control register */
-#define FIMD_WKEYALPHA_START 0x160
-#define FIMD_WKEYALPHA_END 0x16C
-
-/* Dithering control register */
-#define FIMD_DITHMODE 0x170
-
-/* Window alpha control registers */
-#define FIMD_VIDALPHA_ALPHA_LOWER 0x000F0F0F
-#define FIMD_VIDALPHA_ALPHA_UPPER 0x00F0F0F0
-#define FIMD_VIDWALPHA_START 0x21C
-#define FIMD_VIDWALPHA_END 0x240
-
-/* Window color map registers */
-#define FIMD_WINMAP_START 0x180
-#define FIMD_WINMAP_END 0x190
-#define FIMD_WINMAP_EN (1 << 24)
-#define FIMD_WINMAP_COLOR_MASK 0x00FFFFFF
-
-/* Window palette control registers */
-#define FIMD_WPALCON_HIGH 0x019C
-#define FIMD_WPALCON_LOW 0x01A0
-#define FIMD_WPALCON_UPDATEEN (1 << 9)
-#define FIMD_WPAL_W0PAL_L 0x07
-#define FIMD_WPAL_W0PAL_L_SHT 0
-#define FIMD_WPAL_W1PAL_L 0x07
-#define FIMD_WPAL_W1PAL_L_SHT 3
-#define FIMD_WPAL_W2PAL_L 0x01
-#define FIMD_WPAL_W2PAL_L_SHT 6
-#define FIMD_WPAL_W2PAL_H 0x06
-#define FIMD_WPAL_W2PAL_H_SHT 8
-#define FIMD_WPAL_W3PAL_L 0x01
-#define FIMD_WPAL_W3PAL_L_SHT 7
-#define FIMD_WPAL_W3PAL_H 0x06
-#define FIMD_WPAL_W3PAL_H_SHT 12
-#define FIMD_WPAL_W4PAL_L 0x01
-#define FIMD_WPAL_W4PAL_L_SHT 8
-#define FIMD_WPAL_W4PAL_H 0x06
-#define FIMD_WPAL_W4PAL_H_SHT 16
-
-/* Trigger control registers */
-#define FIMD_TRIGCON 0x01A4
-#define FIMD_TRIGCON_ROMASK 0x00000004
-
-/* LCD I80 Interface Control */
-#define FIMD_I80IFCON_START 0x01B0
-#define FIMD_I80IFCON_END 0x01BC
-/* Color gain control register */
-#define FIMD_COLORGAINCON 0x01C0
-/* LCD i80 Interface Command Control */
-#define FIMD_LDI_CMDCON0 0x01D0
-#define FIMD_LDI_CMDCON1 0x01D4
-/* I80 System Interface Manual Command Control */
-#define FIMD_SIFCCON0 0x01E0
-#define FIMD_SIFCCON2 0x01E8
-
-/* Hue Control Registers */
-#define FIMD_HUECOEFCR_START 0x01EC
-#define FIMD_HUECOEFCR_END 0x01F4
-#define FIMD_HUECOEFCB_START 0x01FC
-#define FIMD_HUECOEFCB_END 0x0208
-#define FIMD_HUEOFFSET 0x020C
-
-/* Video interrupt control registers */
-#define FIMD_VIDINT_INTFIFOPEND (1 << 0)
-#define FIMD_VIDINT_INTFRMPEND (1 << 1)
-#define FIMD_VIDINT_INTI80PEND (1 << 2)
-#define FIMD_VIDINT_INTEN (1 << 0)
-#define FIMD_VIDINT_INTFIFOEN (1 << 1)
-#define FIMD_VIDINT_INTFRMEN (1 << 12)
-#define FIMD_VIDINT_I80IFDONE (1 << 17)
-
-/* Window blend equation control registers */
-#define FIMD_BLENDEQ_START 0x0244
-#define FIMD_BLENDEQ_END 0x0250
-#define FIMD_BLENDCON 0x0260
-#define FIMD_ALPHA_8BIT (1 << 0)
-#define FIMD_BLENDEQ_COEF_MASK 0xF
-
-/* Window RTQOS Control Registers */
-#define FIMD_WRTQOSCON_START 0x0264
-#define FIMD_WRTQOSCON_END 0x0274
-
-/* LCD I80 Interface Command */
-#define FIMD_I80IFCMD_START 0x0280
-#define FIMD_I80IFCMD_END 0x02AC
-
-/* Shadow windows control registers */
-#define FIMD_SHD_ADD0_START 0x40A0
-#define FIMD_SHD_ADD0_END 0x40C0
-#define FIMD_SHD_ADD1_START 0x40D0
-#define FIMD_SHD_ADD1_END 0x40F0
-#define FIMD_SHD_ADD2_START 0x4100
-#define FIMD_SHD_ADD2_END 0x4110
-
-/* Palette memory */
-#define FIMD_PAL_MEM_START 0x2400
-#define FIMD_PAL_MEM_END 0x37FC
-/* Palette memory aliases for windows 0 and 1 */
-#define FIMD_PALMEM_AL_START 0x0400
-#define FIMD_PALMEM_AL_END 0x0BFC
-
-typedef struct {
- uint8_t r, g, b;
- /* D[31..24]dummy, D[23..16]rAlpha, D[15..8]gAlpha, D[7..0]bAlpha */
- uint32_t a;
-} rgba;
-#define RGBA_SIZE 7
-
-typedef void pixel_to_rgb_func(uint32_t pixel, rgba *p);
-typedef struct Exynos4210fimdWindow Exynos4210fimdWindow;
-
-struct Exynos4210fimdWindow {
- uint32_t wincon; /* Window control register */
- uint32_t buf_start[3]; /* Start address for video frame buffer */
- uint32_t buf_end[3]; /* End address for video frame buffer */
- uint32_t keycon[2]; /* Window color key registers */
- uint32_t keyalpha; /* Color key alpha control register */
- uint32_t winmap; /* Window color map register */
- uint32_t blendeq; /* Window blending equation control register */
- uint32_t rtqoscon; /* Window RTQOS Control Registers */
- uint32_t palette[256]; /* Palette RAM */
- uint32_t shadow_buf_start; /* Start address of shadow frame buffer */
- uint32_t shadow_buf_end; /* End address of shadow frame buffer */
- uint32_t shadow_buf_size; /* Virtual shadow screen width */
-
- pixel_to_rgb_func *pixel_to_rgb;
- void (*draw_line)(Exynos4210fimdWindow *w, uint8_t *src, uint8_t *dst,
- bool blend);
- uint32_t (*get_alpha)(Exynos4210fimdWindow *w, uint32_t pix_a);
- uint16_t lefttop_x, lefttop_y; /* VIDOSD0 register */
- uint16_t rightbot_x, rightbot_y; /* VIDOSD1 register */
- uint32_t osdsize; /* VIDOSD2&3 register */
- uint32_t alpha_val[2]; /* VIDOSD2&3, VIDWALPHA registers */
- uint16_t virtpage_width; /* VIDWADD2 register */
- uint16_t virtpage_offsize; /* VIDWADD2 register */
- MemoryRegionSection mem_section; /* RAM fragment containing framebuffer */
- uint8_t *host_fb_addr; /* Host pointer to window's framebuffer */
- target_phys_addr_t fb_len; /* Framebuffer length */
-};
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
- DisplayState *console;
- qemu_irq irq[3];
-
- uint32_t vidcon[4]; /* Video main control registers 0-3 */
- uint32_t vidtcon[4]; /* Video time control registers 0-3 */
- uint32_t shadowcon; /* Window shadow control register */
- uint32_t winchmap; /* Channel mapping control register */
- uint32_t vidintcon[2]; /* Video interrupt control registers */
- uint32_t dithmode; /* Dithering control register */
- uint32_t wpalcon[2]; /* Window palette control registers */
- uint32_t trigcon; /* Trigger control register */
- uint32_t i80ifcon[4]; /* I80 interface control registers */
- uint32_t colorgaincon; /* Color gain control register */
- uint32_t ldi_cmdcon[2]; /* LCD I80 interface command control */
- uint32_t sifccon[3]; /* I80 System Interface Manual Command Control */
- uint32_t huecoef_cr[4]; /* Hue control registers */
- uint32_t huecoef_cb[4]; /* Hue control registers */
- uint32_t hueoffset; /* Hue offset control register */
- uint32_t blendcon; /* Blending control register */
- uint32_t i80ifcmd[12]; /* LCD I80 Interface Command */
-
- Exynos4210fimdWindow window[5]; /* Window-specific registers */
- uint8_t *ifb; /* Internal frame buffer */
- bool invalidate; /* Image needs to be redrawn */
- bool enabled; /* Display controller is enabled */
-} Exynos4210fimdState;
-
-/* Perform byte/halfword/word swap of data according to WINCON */
-static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data)
-{
- int i;
- uint64_t res;
- uint64_t x = *data;
-
- if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
- res = 0;
- for (i = 0; i < 64; i++) {
- if (x & (1ULL << (64 - i))) {
- res |= (1ULL << i);
- }
- }
- x = res;
- }
-
- if (swap_ctl & FIMD_WINCON_SWAP_BYTE) {
- x = bswap64(x);
- }
-
- if (swap_ctl & FIMD_WINCON_SWAP_HWORD) {
- x = ((x & 0x000000000000FFFFULL) << 48) |
- ((x & 0x00000000FFFF0000ULL) << 16) |
- ((x & 0x0000FFFF00000000ULL) >> 16) |
- ((x & 0xFFFF000000000000ULL) >> 48);
- }
-
- if (swap_ctl & FIMD_WINCON_SWAP_WORD) {
- x = ((x & 0x00000000FFFFFFFFULL) << 32) |
- ((x & 0xFFFFFFFF00000000ULL) >> 32);
- }
-
- *data = x;
-}
-
-/* Conversion routines of Pixel data from frame buffer area to internal RGBA
- * pixel representation.
- * Every color component internally represented as 8-bit value. If original
- * data has less than 8 bit for component, data is extended to 8 bit. For
- * example, if blue component has only two possible values 0 and 1 it will be
- * extended to 0 and 0xFF */
-
-/* One bit for alpha representation */
-#define DEF_PIXEL_TO_RGB_A1(N, R, G, B) \
-static void N(uint32_t pixel, rgba *p) \
-{ \
- p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
- ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
- pixel >>= (B); \
- p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
- ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
- pixel >>= (G); \
- p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
- ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
- pixel >>= (R); \
- p->a = (pixel & 0x1); \
-}
-
-DEF_PIXEL_TO_RGB_A1(pixel_a444_to_rgb, 4, 4, 4)
-DEF_PIXEL_TO_RGB_A1(pixel_a555_to_rgb, 5, 5, 5)
-DEF_PIXEL_TO_RGB_A1(pixel_a666_to_rgb, 6, 6, 6)
-DEF_PIXEL_TO_RGB_A1(pixel_a665_to_rgb, 6, 6, 5)
-DEF_PIXEL_TO_RGB_A1(pixel_a888_to_rgb, 8, 8, 8)
-DEF_PIXEL_TO_RGB_A1(pixel_a887_to_rgb, 8, 8, 7)
-
-/* Alpha component is always zero */
-#define DEF_PIXEL_TO_RGB_A0(N, R, G, B) \
-static void N(uint32_t pixel, rgba *p) \
-{ \
- p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
- ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
- pixel >>= (B); \
- p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
- ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
- pixel >>= (G); \
- p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
- ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
- p->a = 0x0; \
-}
-
-DEF_PIXEL_TO_RGB_A0(pixel_565_to_rgb, 5, 6, 5)
-DEF_PIXEL_TO_RGB_A0(pixel_555_to_rgb, 5, 5, 5)
-DEF_PIXEL_TO_RGB_A0(pixel_666_to_rgb, 6, 6, 6)
-DEF_PIXEL_TO_RGB_A0(pixel_888_to_rgb, 8, 8, 8)
-
-/* Alpha component has some meaningful value */
-#define DEF_PIXEL_TO_RGB_A(N, R, G, B, A) \
-static void N(uint32_t pixel, rgba *p) \
-{ \
- p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
- ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
- pixel >>= (B); \
- p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
- ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
- pixel >>= (G); \
- p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
- ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
- pixel >>= (R); \
- p->a = (pixel & ((1 << (A)) - 1)) << (8 - (A)) | \
- ((pixel >> (2 * (A) - 8)) & ((1 << (8 - (A))) - 1)); \
- p->a = p->a | (p->a << 8) | (p->a << 16); \
-}
-
-DEF_PIXEL_TO_RGB_A(pixel_4444_to_rgb, 4, 4, 4, 4)
-DEF_PIXEL_TO_RGB_A(pixel_8888_to_rgb, 8, 8, 8, 8)
-
-/* Lookup table to extent 2-bit color component to 8 bit */
-static const uint8_t pixel_lutable_2b[4] = {
- 0x0, 0x55, 0xAA, 0xFF
-};
-/* Lookup table to extent 3-bit color component to 8 bit */
-static const uint8_t pixel_lutable_3b[8] = {
- 0x0, 0x24, 0x49, 0x6D, 0x92, 0xB6, 0xDB, 0xFF
-};
-/* Special case for a232 bpp mode */
-static void pixel_a232_to_rgb(uint32_t pixel, rgba *p)
-{
- p->b = pixel_lutable_2b[(pixel & 0x3)];
- pixel >>= 2;
- p->g = pixel_lutable_3b[(pixel & 0x7)];
- pixel >>= 3;
- p->r = pixel_lutable_2b[(pixel & 0x3)];
- pixel >>= 2;
- p->a = (pixel & 0x1);
-}
-
-/* Special case for (5+1, 5+1, 5+1) mode. Data bit 15 is common LSB
- * for all three color components */
-static void pixel_1555_to_rgb(uint32_t pixel, rgba *p)
-{
- uint8_t comm = (pixel >> 15) & 1;
- p->b = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
- pixel >>= 5;
- p->g = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
- pixel >>= 5;
- p->r = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
- p->a = 0x0;
-}
-
-/* Put/get pixel to/from internal LCD Controller framebuffer */
-
-static int put_pixel_ifb(const rgba p, uint8_t *d)
-{
- *(uint8_t *)d++ = p.r;
- *(uint8_t *)d++ = p.g;
- *(uint8_t *)d++ = p.b;
- *(uint32_t *)d = p.a;
- return RGBA_SIZE;
-}
-
-static int get_pixel_ifb(const uint8_t *s, rgba *p)
-{
- p->r = *(uint8_t *)s++;
- p->g = *(uint8_t *)s++;
- p->b = *(uint8_t *)s++;
- p->a = (*(uint32_t *)s) & 0x00FFFFFF;
- return RGBA_SIZE;
-}
-
-static pixel_to_rgb_func *palette_data_format[8] = {
- [0] = pixel_565_to_rgb,
- [1] = pixel_a555_to_rgb,
- [2] = pixel_666_to_rgb,
- [3] = pixel_a665_to_rgb,
- [4] = pixel_a666_to_rgb,
- [5] = pixel_888_to_rgb,
- [6] = pixel_a888_to_rgb,
- [7] = pixel_8888_to_rgb
-};
-
-/* Returns Index in palette data formats table for given window number WINDOW */
-static uint32_t
-exynos4210_fimd_palette_format(Exynos4210fimdState *s, int window)
-{
- uint32_t ret;
-
- switch (window) {
- case 0:
- ret = (s->wpalcon[1] >> FIMD_WPAL_W0PAL_L_SHT) & FIMD_WPAL_W0PAL_L;
- if (ret != 7) {
- ret = 6 - ret;
- }
- break;
- case 1:
- ret = (s->wpalcon[1] >> FIMD_WPAL_W1PAL_L_SHT) & FIMD_WPAL_W1PAL_L;
- if (ret != 7) {
- ret = 6 - ret;
- }
- break;
- case 2:
- ret = ((s->wpalcon[0] >> FIMD_WPAL_W2PAL_H_SHT) & FIMD_WPAL_W2PAL_H) |
- ((s->wpalcon[1] >> FIMD_WPAL_W2PAL_L_SHT) & FIMD_WPAL_W2PAL_L);
- break;
- case 3:
- ret = ((s->wpalcon[0] >> FIMD_WPAL_W3PAL_H_SHT) & FIMD_WPAL_W3PAL_H) |
- ((s->wpalcon[1] >> FIMD_WPAL_W3PAL_L_SHT) & FIMD_WPAL_W3PAL_L);
- break;
- case 4:
- ret = ((s->wpalcon[0] >> FIMD_WPAL_W4PAL_H_SHT) & FIMD_WPAL_W4PAL_H) |
- ((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SHT) & FIMD_WPAL_W4PAL_L);
- break;
- default:
- hw_error("exynos4210.fimd: incorrect window number %d\n", window);
- ret = 0;
- break;
- }
- return ret;
-}
-
-#define FIMD_1_MINUS_COLOR(x) \
- ((0xFF - ((x) & 0xFF)) | (0xFF00 - ((x) & 0xFF00)) | \
- (0xFF0000 - ((x) & 0xFF0000)))
-#define EXTEND_LOWER_HALFBYTE(x) (((x) & 0xF0F0F) | (((x) << 4) & 0xF0F0F0))
-#define EXTEND_UPPER_HALFBYTE(x) (((x) & 0xF0F0F0) | (((x) >> 4) & 0xF0F0F))
-
-/* Multiply three lower bytes of two 32-bit words with each other.
- * Each byte with values 0-255 is considered as a number with possible values
- * in a range [0 - 1] */
-static inline uint32_t fimd_mult_each_byte(uint32_t a, uint32_t b)
-{
- uint32_t tmp;
- uint32_t ret;
-
- ret = ((tmp = (((a & 0xFF) * (b & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF : tmp;
- ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)) / 0xFF)) > 0xFF) ?
- 0xFF00 : tmp << 8;
- ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
- 0xFF0000 : tmp << 16;
- return ret;
-}
-
-/* For each corresponding bytes of two 32-bit words: (a*b + c*d)
- * Byte values 0-255 are mapped to a range [0 .. 1] */
-static inline uint32_t
-fimd_mult_and_sum_each_byte(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
-{
- uint32_t tmp;
- uint32_t ret;
-
- ret = ((tmp = (((a & 0xFF) * (b & 0xFF) + (c & 0xFF) * (d & 0xFF)) / 0xFF))
- > 0xFF) ? 0xFF : tmp;
- ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF) + ((c >> 8) & 0xFF) *
- ((d >> 8) & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF00 : tmp << 8;
- ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF) +
- ((c >> 16) & 0xFF) * ((d >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
- 0xFF0000 : tmp << 16;
- return ret;
-}
-
-/* These routines cover all possible sources of window's transparent factor
- * used in blending equation. Choice of routine is affected by WPALCON
- * registers, BLENDCON register and window's WINCON register */
-
-static uint32_t fimd_get_alpha_pix(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return pix_a;
-}
-
-static uint32_t
-fimd_get_alpha_pix_extlow(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return EXTEND_LOWER_HALFBYTE(pix_a);
-}
-
-static uint32_t
-fimd_get_alpha_pix_exthigh(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return EXTEND_UPPER_HALFBYTE(pix_a);
-}
-
-static uint32_t fimd_get_alpha_mult(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return fimd_mult_each_byte(pix_a, w->alpha_val[0]);
-}
-
-static uint32_t fimd_get_alpha_mult_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return fimd_mult_each_byte(EXTEND_LOWER_HALFBYTE(pix_a),
- EXTEND_UPPER_HALFBYTE(w->alpha_val[0]));
-}
-
-static uint32_t fimd_get_alpha_aen(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return w->alpha_val[pix_a];
-}
-
-static uint32_t fimd_get_alpha_aen_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return EXTEND_UPPER_HALFBYTE(w->alpha_val[pix_a]);
-}
-
-static uint32_t fimd_get_alpha_sel(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return w->alpha_val[(w->wincon & FIMD_WINCON_ALPHA_SEL) ? 1 : 0];
-}
-
-static uint32_t fimd_get_alpha_sel_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
-{
- return EXTEND_UPPER_HALFBYTE(w->alpha_val[(w->wincon &
- FIMD_WINCON_ALPHA_SEL) ? 1 : 0]);
-}
-
-/* Updates currently active alpha value get function for specified window */
-static void fimd_update_get_alpha(Exynos4210fimdState *s, int win)
-{
- Exynos4210fimdWindow *w = &s->window[win];
- const bool alpha_is_8bit = s->blendcon & FIMD_ALPHA_8BIT;
-
- if (w->wincon & FIMD_WINCON_BLD_PIX) {
- if ((w->wincon & FIMD_WINCON_ALPHA_SEL) && WIN_BPP_MODE_WITH_ALPHA(w)) {
- /* In this case, alpha component contains meaningful value */
- if (w->wincon & FIMD_WINCON_ALPHA_MUL) {
- w->get_alpha = alpha_is_8bit ?
- fimd_get_alpha_mult : fimd_get_alpha_mult_ext;
- } else {
- w->get_alpha = alpha_is_8bit ?
- fimd_get_alpha_pix : fimd_get_alpha_pix_extlow;
- }
- } else {
- if (IS_PALETTIZED_MODE(w) &&
- PAL_MODE_WITH_ALPHA(exynos4210_fimd_palette_format(s, win))) {
- /* Alpha component has 8-bit numeric value */
- w->get_alpha = alpha_is_8bit ?
- fimd_get_alpha_pix : fimd_get_alpha_pix_exthigh;
- } else {
- /* Alpha has only two possible values (AEN) */
- w->get_alpha = alpha_is_8bit ?
- fimd_get_alpha_aen : fimd_get_alpha_aen_ext;
- }
- }
- } else {
- w->get_alpha = alpha_is_8bit ? fimd_get_alpha_sel :
- fimd_get_alpha_sel_ext;
- }
-}
-
-/* Blends current window's (w) pixel (foreground pixel *ret) with background
- * window (w_blend) pixel p_bg according to formula:
- * NEW_COLOR = a_coef x FG_PIXEL_COLOR + b_coef x BG_PIXEL_COLOR
- * NEW_ALPHA = p_coef x FG_ALPHA + q_coef x BG_ALPHA
- */
-static void
-exynos4210_fimd_blend_pixel(Exynos4210fimdWindow *w, rgba p_bg, rgba *ret)
-{
- rgba p_fg = *ret;
- uint32_t bg_color = ((p_bg.r & 0xFF) << 16) | ((p_bg.g & 0xFF) << 8) |
- (p_bg.b & 0xFF);
- uint32_t fg_color = ((p_fg.r & 0xFF) << 16) | ((p_fg.g & 0xFF) << 8) |
- (p_fg.b & 0xFF);
- uint32_t alpha_fg = p_fg.a;
- int i;
- /* It is possible that blending equation parameters a and b do not
- * depend on window BLENEQ register. Account for this with first_coef */
- enum { A_COEF = 0, B_COEF = 1, P_COEF = 2, Q_COEF = 3, COEF_NUM = 4};
- uint32_t first_coef = A_COEF;
- uint32_t blend_param[COEF_NUM];
-
- if (w->keycon[0] & FIMD_WKEYCON0_KEYEN) {
- uint32_t colorkey = (w->keycon[1] &
- ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) & FIMD_WKEYCON0_COMPKEY;
-
- if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) &&
- (bg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
- /* Foreground pixel is displayed */
- if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
- alpha_fg = w->keyalpha;
- blend_param[A_COEF] = alpha_fg;
- blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
- } else {
- alpha_fg = 0;
- blend_param[A_COEF] = 0xFFFFFF;
- blend_param[B_COEF] = 0x0;
- }
- first_coef = P_COEF;
- } else if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) == 0 &&
- (fg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
- /* Background pixel is displayed */
- if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
- alpha_fg = w->keyalpha;
- blend_param[A_COEF] = alpha_fg;
- blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
- } else {
- alpha_fg = 0;
- blend_param[A_COEF] = 0x0;
- blend_param[B_COEF] = 0xFFFFFF;
- }
- first_coef = P_COEF;
- }
- }
-
- for (i = first_coef; i < COEF_NUM; i++) {
- switch ((w->blendeq >> i * 6) & FIMD_BLENDEQ_COEF_MASK) {
- case 0:
- blend_param[i] = 0;
- break;
- case 1:
- blend_param[i] = 0xFFFFFF;
- break;
- case 2:
- blend_param[i] = alpha_fg;
- break;
- case 3:
- blend_param[i] = FIMD_1_MINUS_COLOR(alpha_fg);
- break;
- case 4:
- blend_param[i] = p_bg.a;
- break;
- case 5:
- blend_param[i] = FIMD_1_MINUS_COLOR(p_bg.a);
- break;
- case 6:
- blend_param[i] = w->alpha_val[0];
- break;
- case 10:
- blend_param[i] = fg_color;
- break;
- case 11:
- blend_param[i] = FIMD_1_MINUS_COLOR(fg_color);
- break;
- case 12:
- blend_param[i] = bg_color;
- break;
- case 13:
- blend_param[i] = FIMD_1_MINUS_COLOR(bg_color);
- break;
- default:
- hw_error("exynos4210.fimd: blend equation coef illegal value\n");
- break;
- }
- }
-
- fg_color = fimd_mult_and_sum_each_byte(bg_color, blend_param[B_COEF],
- fg_color, blend_param[A_COEF]);
- ret->b = fg_color & 0xFF;
- fg_color >>= 8;
- ret->g = fg_color & 0xFF;
- fg_color >>= 8;
- ret->r = fg_color & 0xFF;
- ret->a = fimd_mult_and_sum_each_byte(alpha_fg, blend_param[P_COEF],
- p_bg.a, blend_param[Q_COEF]);
-}
-
-/* These routines read data from video frame buffer in system RAM, convert
- * this data to display controller internal representation, if necessary,
- * perform pixel blending with data, currently presented in internal buffer.
- * Result is stored in display controller internal frame buffer. */
-
-/* Draw line with index in palette table in RAM frame buffer data */
-#define DEF_DRAW_LINE_PALETTE(N) \
-static void glue(draw_line_palette_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
- uint8_t *dst, bool blend) \
-{ \
- int width = w->rightbot_x - w->lefttop_x + 1; \
- uint8_t *ifb = dst; \
- uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
- uint64_t data; \
- rgba p, p_old; \
- int i; \
- do { \
- data = ldq_raw((void *)src); \
- src += 8; \
- fimd_swap_data(swap, &data); \
- for (i = (64 / (N) - 1); i >= 0; i--) { \
- w->pixel_to_rgb(w->palette[(data >> ((N) * i)) & \
- ((1ULL << (N)) - 1)], &p); \
- p.a = w->get_alpha(w, p.a); \
- if (blend) { \
- ifb += get_pixel_ifb(ifb, &p_old); \
- exynos4210_fimd_blend_pixel(w, p_old, &p); \
- } \
- dst += put_pixel_ifb(p, dst); \
- } \
- width -= (64 / (N)); \
- } while (width > 0); \
-}
-
-/* Draw line with direct color value in RAM frame buffer data */
-#define DEF_DRAW_LINE_NOPALETTE(N) \
-static void glue(draw_line_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
- uint8_t *dst, bool blend) \
-{ \
- int width = w->rightbot_x - w->lefttop_x + 1; \
- uint8_t *ifb = dst; \
- uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
- uint64_t data; \
- rgba p, p_old; \
- int i; \
- do { \
- data = ldq_raw((void *)src); \
- src += 8; \
- fimd_swap_data(swap, &data); \
- for (i = (64 / (N) - 1); i >= 0; i--) { \
- w->pixel_to_rgb((data >> ((N) * i)) & ((1ULL << (N)) - 1), &p); \
- p.a = w->get_alpha(w, p.a); \
- if (blend) { \
- ifb += get_pixel_ifb(ifb, &p_old); \
- exynos4210_fimd_blend_pixel(w, p_old, &p); \
- } \
- dst += put_pixel_ifb(p, dst); \
- } \
- width -= (64 / (N)); \
- } while (width > 0); \
-}
-
-DEF_DRAW_LINE_PALETTE(1)
-DEF_DRAW_LINE_PALETTE(2)
-DEF_DRAW_LINE_PALETTE(4)
-DEF_DRAW_LINE_PALETTE(8)
-DEF_DRAW_LINE_NOPALETTE(8) /* 8bpp mode has palette and non-palette versions */
-DEF_DRAW_LINE_NOPALETTE(16)
-DEF_DRAW_LINE_NOPALETTE(32)
-
-/* Special draw line routine for window color map case */
-static void draw_line_mapcolor(Exynos4210fimdWindow *w, uint8_t *src,
- uint8_t *dst, bool blend)
-{
- rgba p, p_old;
- uint8_t *ifb = dst;
- int width = w->rightbot_x - w->lefttop_x + 1;
- uint32_t map_color = w->winmap & FIMD_WINMAP_COLOR_MASK;
-
- do {
- pixel_888_to_rgb(map_color, &p);
- p.a = w->get_alpha(w, p.a);
- if (blend) {
- ifb += get_pixel_ifb(ifb, &p_old);
- exynos4210_fimd_blend_pixel(w, p_old, &p);
- }
- dst += put_pixel_ifb(p, dst);
- } while (--width);
-}
-
-/* Write RGB to QEMU's GraphicConsole framebuffer */
-
-static int put_to_qemufb_pixel8(const rgba p, uint8_t *d)
-{
- uint32_t pixel;
- uint8_t alpha;
-
- if ( brightness_level < BRIGHTNESS_MAX ) {
- alpha = brightness_tbl[brightness_level];
- pixel = rgb_to_pixel8(alpha * p.r >> 8, alpha * p.g >> 8,
- alpha * p.b >> 8);
- } else {
- pixel = rgb_to_pixel8(p.r, p.g, p.b);
- }
- *(uint8_t *)d = pixel;
- return 1;
-}
-
-static int put_to_qemufb_pixel15(const rgba p, uint8_t *d)
-{
- uint32_t pixel;
- uint8_t alpha;
-
- if ( brightness_level < BRIGHTNESS_MAX ) {
- alpha = brightness_tbl[brightness_level];
- pixel = rgb_to_pixel15(alpha * p.r >> 8, alpha * p.g >> 8,
- alpha * p.b >> 8);
- } else {
- pixel = rgb_to_pixel15(p.r, p.g, p.b);
- }
- *(uint16_t *)d = pixel;
- return 2;
-}
-
-static int put_to_qemufb_pixel16(const rgba p, uint8_t *d)
-{
- uint32_t pixel;
- uint8_t alpha;
-
- if ( brightness_level < BRIGHTNESS_MAX ) {
- alpha = brightness_tbl[brightness_level];
- pixel = rgb_to_pixel16(alpha * p.r >> 8, alpha * p.g >> 8,
- alpha * p.b >> 8);
- } else {
- pixel = rgb_to_pixel16(p.r, p.g, p.b);
- }
- *(uint16_t *)d = pixel;
- return 2;
-}
-
-static int put_to_qemufb_pixel24(const rgba p, uint8_t *d)
-{
- uint32_t pixel;
- uint8_t alpha;
-
- if ( brightness_level < BRIGHTNESS_MAX ) {
- alpha = brightness_tbl[brightness_level];
- pixel = rgb_to_pixel24(alpha * p.r >> 8, alpha * p.g >> 8,
- alpha * p.b >> 8);
- } else {
- pixel = rgb_to_pixel24(p.r, p.g, p.b);
- }
- *(uint8_t *)d++ = (pixel >> 0) & 0xFF;
- *(uint8_t *)d++ = (pixel >> 8) & 0xFF;
- *(uint8_t *)d++ = (pixel >> 16) & 0xFF;
- return 3;
-}
-
-static int put_to_qemufb_pixel32(const rgba p, uint8_t *d)
-{
- uint32_t pixel;
- uint8_t alpha;
-
- if ( brightness_level < BRIGHTNESS_MAX ) {
- alpha = brightness_tbl[brightness_level];
- pixel = rgb_to_pixel24(alpha * p.r >> 8, alpha * p.g >> 8,
- alpha * p.b >> 8);
- } else {
- pixel = rgb_to_pixel24(p.r, p.g, p.b);
- }
- *(uint32_t *)d = pixel;
- return 4;
-}
-
-/* Routine to copy pixel from internal buffer to QEMU buffer */
-static int (*put_pixel_toqemu)(const rgba p, uint8_t *pixel);
-static inline void fimd_update_putpix_qemu(int bpp)
-{
- switch (bpp) {
- case 8:
- put_pixel_toqemu = put_to_qemufb_pixel8;
- break;
- case 15:
- put_pixel_toqemu = put_to_qemufb_pixel15;
- break;
- case 16:
- put_pixel_toqemu = put_to_qemufb_pixel16;
- break;
- case 24:
- put_pixel_toqemu = put_to_qemufb_pixel24;
- break;
- case 32:
- put_pixel_toqemu = put_to_qemufb_pixel32;
- break;
- default:
- hw_error("exynos4210.fimd: unsupported BPP (%d)", bpp);
- break;
- }
-}
-
-/* Routine to copy a line from internal frame buffer to QEMU display */
-static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst)
-{
- rgba p;
-
- do {
- src += get_pixel_ifb(src, &p);
- dst += put_pixel_toqemu(p, dst);
- } while (--width);
-}
-
-/* Parse BPPMODE_F = WINCON1[5:2] bits */
-static void exynos4210_fimd_update_win_bppmode(Exynos4210fimdState *s, int win)
-{
- Exynos4210fimdWindow *w = &s->window[win];
-
- if (w->winmap & FIMD_WINMAP_EN) {
- w->draw_line = draw_line_mapcolor;
- return;
- }
-
- switch (WIN_BPP_MODE(w)) {
- case 0:
- w->draw_line = draw_line_palette_1;
- w->pixel_to_rgb =
- palette_data_format[exynos4210_fimd_palette_format(s, win)];
- break;
- case 1:
- w->draw_line = draw_line_palette_2;
- w->pixel_to_rgb =
- palette_data_format[exynos4210_fimd_palette_format(s, win)];
- break;
- case 2:
- w->draw_line = draw_line_palette_4;
- w->pixel_to_rgb =
- palette_data_format[exynos4210_fimd_palette_format(s, win)];
- break;
- case 3:
- w->draw_line = draw_line_palette_8;
- w->pixel_to_rgb =
- palette_data_format[exynos4210_fimd_palette_format(s, win)];
- break;
- case 4:
- w->draw_line = draw_line_8;
- w->pixel_to_rgb = pixel_a232_to_rgb;
- break;
- case 5:
- w->draw_line = draw_line_16;
- w->pixel_to_rgb = pixel_565_to_rgb;
- break;
- case 6:
- w->draw_line = draw_line_16;
- w->pixel_to_rgb = pixel_a555_to_rgb;
- break;
- case 7:
- w->draw_line = draw_line_16;
- w->pixel_to_rgb = pixel_1555_to_rgb;
- break;
- case 8:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_666_to_rgb;
- break;
- case 9:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_a665_to_rgb;
- break;
- case 10:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_a666_to_rgb;
- break;
- case 11:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_888_to_rgb;
- break;
- case 12:
- w->draw_line = draw_line_32;
- w->pixel_to_rgb = pixel_a887_to_rgb;
- break;
- case 13:
- w->draw_line = draw_line_32;
- if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
- FIMD_WINCON_ALPHA_SEL)) {
- w->pixel_to_rgb = pixel_8888_to_rgb;
- } else {
- w->pixel_to_rgb = pixel_a888_to_rgb;
- }
- break;
- case 14:
- w->draw_line = draw_line_16;
- if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
- FIMD_WINCON_ALPHA_SEL)) {
- w->pixel_to_rgb = pixel_4444_to_rgb;
- } else {
- w->pixel_to_rgb = pixel_a444_to_rgb;
- }
- break;
- case 15:
- w->draw_line = draw_line_16;
- w->pixel_to_rgb = pixel_555_to_rgb;
- break;
- }
-}
-
-#if EXYNOS4210_FIMD_MODE_TRACE > 0
-static const char *exynos4210_fimd_get_bppmode(int mode_code)
-{
- switch (mode_code) {
- case 0:
- return "1 bpp";
- case 1:
- return "2 bpp";
- case 2:
- return "4 bpp";
- case 3:
- return "8 bpp (palettized)";
- case 4:
- return "8 bpp (non-palettized, A: 1-R:2-G:3-B:2)";
- case 5:
- return "16 bpp (non-palettized, R:5-G:6-B:5)";
- case 6:
- return "16 bpp (non-palettized, A:1-R:5-G:5-B:5)";
- case 7:
- return "16 bpp (non-palettized, I :1-R:5-G:5-B:5)";
- case 8:
- return "Unpacked 18 bpp (non-palettized, R:6-G:6-B:6)";
- case 9:
- return "Unpacked 18bpp (non-palettized,A:1-R:6-G:6-B:5)";
- case 10:
- return "Unpacked 19bpp (non-palettized,A:1-R:6-G:6-B:6)";
- case 11:
- return "Unpacked 24 bpp (non-palettized R:8-G:8-B:8)";
- case 12:
- return "Unpacked 24 bpp (non-palettized A:1-R:8-G:8-B:7)";
- case 13:
- return "Unpacked 25 bpp (non-palettized A:1-R:8-G:8-B:8)";
- case 14:
- return "Unpacked 13 bpp (non-palettized A:1-R:4-G:4-B:4)";
- case 15:
- return "Unpacked 15 bpp (non-palettized R:5-G:5-B:5)";
- default:
- return "Non-existing bpp mode";
- }
-}
-
-static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
- int win_num, uint32_t val)
-{
- Exynos4210fimdWindow *w = &s->window[win_num];
-
- if (w->winmap & FIMD_WINMAP_EN) {
- printf("QEMU FIMD: Window %d is mapped with MAPCOLOR=0x%x\n",
- win_num, w->winmap & 0xFFFFFF);
- return;
- }
-
- if ((val != 0xFFFFFFFF) && ((w->wincon >> 2) & 0xF) == ((val >> 2) & 0xF)) {
- return;
- }
- printf("QEMU FIMD: Window %d BPP mode set to %s\n", win_num,
- exynos4210_fimd_get_bppmode((val >> 2) & 0xF));
-}
-#else
-static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
- int win_num, uint32_t val)
-{
-
-}
-#endif
-
-static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w)
-{
- switch (w->wincon & FIMD_WINCON_BUFSTATUS) {
- case FIMD_WINCON_BUF0_STAT:
- return 0;
- case FIMD_WINCON_BUF1_STAT:
- return 1;
- case FIMD_WINCON_BUF2_STAT:
- return 2;
- default:
- DPRINT_ERROR("Non-existent buffer index\n");
- return 0;
- }
-}
-
-/* Updates specified window's MemorySection based on values of WINCON,
- * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */
-static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
-{
- Exynos4210fimdWindow *w = &s->window[win];
- target_phys_addr_t fb_start_addr, fb_mapped_len;
-
- if (!s->enabled || !(w->wincon & FIMD_WINCON_ENWIN) ||
- FIMD_WINDOW_PROTECTED(s->shadowcon, win)) {
- return;
- }
-
- if (w->host_fb_addr) {
- cpu_physical_memory_unmap(w->host_fb_addr, w->fb_len, 0, 0);
- w->host_fb_addr = NULL;
- w->fb_len = 0;
- }
-
- fb_start_addr = w->buf_start[fimd_get_buffer_id(w)];
- /* Total number of bytes of virtual screen used by current window */
- w->fb_len = fb_mapped_len = (w->virtpage_width + w->virtpage_offsize) *
- (w->rightbot_y - w->lefttop_y + 1);
- w->mem_section = memory_region_find(sysbus_address_space(&s->busdev),
- fb_start_addr, w->fb_len);
- assert(w->mem_section.mr);
- assert(w->mem_section.offset_within_address_space == fb_start_addr);
- DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n",
- win, fb_start_addr, w->fb_len);
-
- if (w->mem_section.size != w->fb_len ||
- !memory_region_is_ram(w->mem_section.mr)) {
- DPRINT_ERROR("Failed to find window %u framebuffer region\n", win);
- goto error_return;
- }
-
- w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len, 0);
- if (!w->host_fb_addr) {
- DPRINT_ERROR("Failed to map window %u framebuffer\n", win);
- goto error_return;
- }
-
- if (fb_mapped_len != w->fb_len) {
- DPRINT_ERROR("Window %u mapped framebuffer length is less then "
- "expected\n", win);
- cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
- goto error_return;
- }
- return;
-
-error_return:
- w->mem_section.mr = NULL;
- w->mem_section.size = 0;
- w->host_fb_addr = NULL;
- w->fb_len = 0;
-}
-
-static void exynos4210_fimd_enable(Exynos4210fimdState *s, bool enabled)
-{
- if (enabled && !s->enabled) {
- unsigned w;
- s->enabled = true;
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- fimd_update_memory_section(s, w);
- }
- }
- s->enabled = enabled;
- DPRINT_TRACE("display controller %s\n", enabled ? "enabled" : "disabled");
-}
-
-static inline uint32_t unpack_upper_4(uint32_t x)
-{
- return ((x & 0xF00) << 12) | ((x & 0xF0) << 8) | ((x & 0xF) << 4);
-}
-
-static inline uint32_t pack_upper_4(uint32_t x)
-{
- return (((x & 0xF00000) >> 12) | ((x & 0xF000) >> 8) |
- ((x & 0xF0) >> 4)) & 0xFFF;
-}
-
-static void exynos4210_fimd_update_irq(Exynos4210fimdState *s)
-{
- if (!(s->vidintcon[0] & FIMD_VIDINT_INTEN)) {
- qemu_irq_lower(s->irq[0]);
- qemu_irq_lower(s->irq[1]);
- qemu_irq_lower(s->irq[2]);
- return;
- }
- if ((s->vidintcon[0] & FIMD_VIDINT_INTFIFOEN) &&
- (s->vidintcon[1] & FIMD_VIDINT_INTFIFOPEND)) {
- qemu_irq_raise(s->irq[0]);
- } else {
- qemu_irq_lower(s->irq[0]);
- }
- if ((s->vidintcon[0] & FIMD_VIDINT_INTFRMEN) &&
- (s->vidintcon[1] & FIMD_VIDINT_INTFRMPEND)) {
- qemu_irq_raise(s->irq[1]);
- } else {
- qemu_irq_lower(s->irq[1]);
- }
- if ((s->vidintcon[0] & FIMD_VIDINT_I80IFDONE) &&
- (s->vidintcon[1] & FIMD_VIDINT_INTI80PEND)) {
- qemu_irq_raise(s->irq[2]);
- } else {
- qemu_irq_lower(s->irq[2]);
- }
-}
-
-static void exynos4210_fimd_invalidate(void *opaque)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- s->invalidate = true;
-}
-
-static void exynos4210_update_resolution(Exynos4210fimdState *s)
-{
- /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */
- uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) &
- FIMD_VIDTCON2_SIZE_MASK) + 1;
- uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
- FIMD_VIDTCON2_SIZE_MASK) + 1;
-
- if (s->ifb == NULL || ds_get_width(s->console) != width ||
- ds_get_height(s->console) != height) {
- DPRINT_L1("Resolution changed from %ux%u to %ux%u\n",
- ds_get_width(s->console), ds_get_height(s->console), width, height);
- qemu_console_resize(s->console, width, height);
- s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1);
- memset(s->ifb, 0, width * height * RGBA_SIZE + 1);
- exynos4210_fimd_invalidate(s);
- }
-}
-
-static void exynos4210_fimd_update(void *opaque)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- Exynos4210fimdWindow *w;
- int i, line;
- target_phys_addr_t fb_line_addr, inc_size;
- int scrn_height;
- int first_line = -1, last_line = -1, scrn_width;
- bool blend = false;
- uint8_t *host_fb_addr;
- bool is_dirty = false;
- const int global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
- const int global_height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
- FIMD_VIDTCON2_SIZE_MASK) + 1;
-
- if (!s || !s->console || !ds_get_bits_per_pixel(s->console) ||
- !s->enabled) {
- return;
- }
- exynos4210_update_resolution(s);
-
- for (i = 0; i < NUM_OF_WINDOWS; i++) {
- w = &s->window[i];
- if ((w->wincon & FIMD_WINCON_ENWIN) && w->host_fb_addr) {
- scrn_height = w->rightbot_y - w->lefttop_y + 1;
- scrn_width = w->virtpage_width;
- /* Total width of virtual screen page in bytes */
- inc_size = scrn_width + w->virtpage_offsize;
- memory_region_sync_dirty_bitmap(w->mem_section.mr);
- host_fb_addr = w->host_fb_addr;
- fb_line_addr = w->mem_section.offset_within_region;
-
- for (line = 0; line < scrn_height; line++) {
- is_dirty = memory_region_get_dirty(w->mem_section.mr,
- fb_line_addr, scrn_width, DIRTY_MEMORY_VGA);
-
- if (s->invalidate || is_dirty) {
- if (first_line == -1) {
- first_line = line;
- }
- last_line = line;
- w->draw_line(w, host_fb_addr, s->ifb +
- w->lefttop_x * RGBA_SIZE + (w->lefttop_y + line) *
- global_width * RGBA_SIZE, blend);
- }
-
- host_fb_addr += inc_size;
- fb_line_addr += inc_size;
- is_dirty = false;
- }
- memory_region_reset_dirty(w->mem_section.mr,
- w->mem_section.offset_within_region,
- w->fb_len, DIRTY_MEMORY_VGA);
- blend = true;
- }
- }
-
- /* Copy resulting image to QEMU_CONSOLE. */
- if (first_line >= 0) {
- uint8_t *d;
- int bpp;
-
- bpp = ds_get_bits_per_pixel(s->console);
- fimd_update_putpix_qemu(bpp);
- bpp = (bpp + 1) >> 3;
- d = ds_get_data(s->console);
- for (line = first_line; line <= last_line; line++) {
- fimd_copy_line_toqemu(global_width, s->ifb + global_width * line *
- RGBA_SIZE, d + global_width * line * bpp);
- }
- dpy_update(s->console, 0, 0, global_width, global_height);
- }
- s->invalidate = false;
- s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
- if ((s->vidcon[0] & FIMD_VIDCON0_ENVID_F) == 0) {
- exynos4210_fimd_enable(s, false);
- }
- exynos4210_fimd_update_irq(s);
-}
-
-static void exynos4210_fimd_reset(DeviceState *d)
-{
- Exynos4210fimdState *s = DO_UPCAST(Exynos4210fimdState, busdev.qdev, d);
- unsigned w;
-
- DPRINT_TRACE("Display controller reset\n");
- /* Set all display controller registers to 0 */
- memset(&s->vidcon, 0, (uint8_t *)&s->window - (uint8_t *)&s->vidcon);
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- memset(&s->window[w], 0, sizeof(Exynos4210fimdWindow));
- s->window[w].blendeq = 0xC2;
- exynos4210_fimd_update_win_bppmode(s, w);
- exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
- fimd_update_get_alpha(s, w);
- }
-
- if (s->ifb != NULL) {
- g_free(s->ifb);
- }
- s->ifb = NULL;
-
- exynos4210_fimd_invalidate(s);
- exynos4210_fimd_enable(s, false);
- /* Some registers have non-zero initial values */
- s->winchmap = 0x7D517D51;
- s->colorgaincon = 0x10040100;
- s->huecoef_cr[0] = s->huecoef_cr[3] = 0x01000100;
- s->huecoef_cb[0] = s->huecoef_cb[3] = 0x01000100;
- s->hueoffset = 0x01800080;
-}
-
-static void exynos4210_fimd_write(void *opaque, target_phys_addr_t offset,
- uint64_t val, unsigned size)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- unsigned w, i;
- uint32_t old_value;
-
- DPRINT_L2("write offset 0x%08x, value=%llu(0x%08llx)\n", offset,
- (long long unsigned int)val, (long long unsigned int)val);
-
- switch (offset) {
- case FIMD_VIDCON0:
- if ((val & FIMD_VIDCON0_ENVID_MASK) == FIMD_VIDCON0_ENVID_MASK) {
- exynos4210_fimd_enable(s, true);
- } else {
- if ((val & FIMD_VIDCON0_ENVID) == 0) {
- exynos4210_fimd_enable(s, false);
- }
- }
- s->vidcon[0] = val;
- break;
- case FIMD_VIDCON1:
- /* Leave read-only bits as is */
- val = (val & (~FIMD_VIDCON1_ROMASK)) |
- (s->vidcon[1] & FIMD_VIDCON1_ROMASK);
- s->vidcon[1] = val;
- break;
- case FIMD_VIDCON2 ... FIMD_VIDCON3:
- s->vidcon[(offset) >> 2] = val;
- break;
- case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
- s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2] = val;
- break;
- case FIMD_WINCON_START ... FIMD_WINCON_END:
- w = (offset - FIMD_WINCON_START) >> 2;
- /* Window's current buffer ID */
- i = fimd_get_buffer_id(&s->window[w]);
- old_value = s->window[w].wincon;
- val = (val & ~FIMD_WINCON_ROMASK) |
- (s->window[w].wincon & FIMD_WINCON_ROMASK);
- if (w == 0) {
- /* Window 0 wincon ALPHA_MUL bit must always be 0 */
- val &= ~FIMD_WINCON_ALPHA_MUL;
- }
- exynos4210_fimd_trace_bppmode(s, w, val);
- switch (val & FIMD_WINCON_BUFSELECT) {
- case FIMD_WINCON_BUF0_SEL:
- val &= ~FIMD_WINCON_BUFSTATUS;
- break;
- case FIMD_WINCON_BUF1_SEL:
- val = (val & ~FIMD_WINCON_BUFSTAT_H) | FIMD_WINCON_BUFSTAT_L;
- break;
- case FIMD_WINCON_BUF2_SEL:
- if (val & FIMD_WINCON_BUFMODE) {
- val = (val & ~FIMD_WINCON_BUFSTAT_L) | FIMD_WINCON_BUFSTAT_H;
- }
- break;
- default:
- break;
- }
- s->window[w].wincon = val;
- exynos4210_fimd_update_win_bppmode(s, w);
- fimd_update_get_alpha(s, w);
- if ((i != fimd_get_buffer_id(&s->window[w])) ||
- (!(old_value & FIMD_WINCON_ENWIN) && (s->window[w].wincon &
- FIMD_WINCON_ENWIN))) {
- fimd_update_memory_section(s, w);
- }
- break;
- case FIMD_SHADOWCON:
- old_value = s->shadowcon;
- s->shadowcon = val;
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- if (FIMD_WINDOW_PROTECTED(old_value, w) &&
- !FIMD_WINDOW_PROTECTED(s->shadowcon, w)) {
- fimd_update_memory_section(s, w);
- }
- }
- break;
- case FIMD_WINCHMAP:
- s->winchmap = val;
- break;
- case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
- w = (offset - FIMD_VIDOSD_START) >> 4;
- i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
- switch (i) {
- case 0:
- old_value = s->window[w].lefttop_y;
- s->window[w].lefttop_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
- FIMD_VIDOSD_COORD_MASK;
- s->window[w].lefttop_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
- FIMD_VIDOSD_COORD_MASK;
- if (s->window[w].lefttop_y != old_value) {
- fimd_update_memory_section(s, w);
- }
- break;
- case 1:
- old_value = s->window[w].rightbot_y;
- s->window[w].rightbot_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
- FIMD_VIDOSD_COORD_MASK;
- s->window[w].rightbot_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
- FIMD_VIDOSD_COORD_MASK;
- if (s->window[w].rightbot_y != old_value) {
- fimd_update_memory_section(s, w);
- }
- break;
- case 2:
- if (w == 0) {
- s->window[w].osdsize = val;
- } else {
- s->window[w].alpha_val[0] =
- unpack_upper_4((val & FIMD_VIDOSD_ALPHA_AEN0) >>
- FIMD_VIDOSD_AEN0_SHIFT) |
- (s->window[w].alpha_val[0] & FIMD_VIDALPHA_ALPHA_LOWER);
- s->window[w].alpha_val[1] =
- unpack_upper_4(val & FIMD_VIDOSD_ALPHA_AEN1) |
- (s->window[w].alpha_val[1] & FIMD_VIDALPHA_ALPHA_LOWER);
- }
- break;
- case 3:
- if (w != 1 && w != 2) {
- DPRINT_ERROR("Bad write offset 0x%08x\n", offset);
- return;
- }
- s->window[w].osdsize = val;
- break;
- }
- break;
- case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
- w = (offset - FIMD_VIDWADD0_START) >> 3;
- i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
- if (i == fimd_get_buffer_id(&s->window[w]) &&
- s->window[w].buf_start[i] != val) {
- s->window[w].buf_start[i] = val;
- fimd_update_memory_section(s, w);
- break;
- }
- s->window[w].buf_start[i] = val;
- break;
- case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
- w = (offset - FIMD_VIDWADD1_START) >> 3;
- i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
- s->window[w].buf_end[i] = val;
- break;
- case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
- w = (offset - FIMD_VIDWADD2_START) >> 2;
- if (((val & FIMD_VIDWADD2_PAGEWIDTH) != s->window[w].virtpage_width) ||
- (((val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE) !=
- s->window[w].virtpage_offsize)) {
- s->window[w].virtpage_width = val & FIMD_VIDWADD2_PAGEWIDTH;
- s->window[w].virtpage_offsize =
- (val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE;
- fimd_update_memory_section(s, w);
- }
- break;
- case FIMD_VIDINTCON0:
- s->vidintcon[0] = val;
- break;
- case FIMD_VIDINTCON1:
- s->vidintcon[1] &= ~(val & 7);
- exynos4210_fimd_update_irq(s);
- break;
- case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
- w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
- i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
- s->window[w].keycon[i] = val;
- break;
- case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
- w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
- s->window[w].keyalpha = val;
- break;
- case FIMD_DITHMODE:
- s->dithmode = val;
- break;
- case FIMD_WINMAP_START ... FIMD_WINMAP_END:
- w = (offset - FIMD_WINMAP_START) >> 2;
- old_value = s->window[w].winmap;
- s->window[w].winmap = val;
- if ((val & FIMD_WINMAP_EN) ^ (old_value & FIMD_WINMAP_EN)) {
- exynos4210_fimd_invalidate(s);
- exynos4210_fimd_update_win_bppmode(s, w);
- exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
- exynos4210_fimd_update(s);
- }
- break;
- case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
- i = (offset - FIMD_WPALCON_HIGH) >> 2;
- s->wpalcon[i] = val;
- if (s->wpalcon[1] & FIMD_WPALCON_UPDATEEN) {
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- exynos4210_fimd_update_win_bppmode(s, w);
- fimd_update_get_alpha(s, w);
- }
- }
- break;
- case FIMD_TRIGCON:
- val = (val & ~FIMD_TRIGCON_ROMASK) | (s->trigcon & FIMD_TRIGCON_ROMASK);
- s->trigcon = val;
- break;
- case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
- s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2] = val;
- break;
- case FIMD_COLORGAINCON:
- s->colorgaincon = val;
- break;
- case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
- s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2] = val;
- break;
- case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
- i = (offset - FIMD_SIFCCON0) >> 2;
- if (i != 2) {
- s->sifccon[i] = val;
- }
- break;
- case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
- i = (offset - FIMD_HUECOEFCR_START) >> 2;
- s->huecoef_cr[i] = val;
- break;
- case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
- i = (offset - FIMD_HUECOEFCB_START) >> 2;
- s->huecoef_cb[i] = val;
- break;
- case FIMD_HUEOFFSET:
- s->hueoffset = val;
- break;
- case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
- w = ((offset - FIMD_VIDWALPHA_START) >> 3);
- i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
- if (w == 0) {
- s->window[w].alpha_val[i] = val;
- } else {
- s->window[w].alpha_val[i] = (val & FIMD_VIDALPHA_ALPHA_LOWER) |
- (s->window[w].alpha_val[i] & FIMD_VIDALPHA_ALPHA_UPPER);
- }
- break;
- case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
- s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq = val;
- break;
- case FIMD_BLENDCON:
- old_value = s->blendcon;
- s->blendcon = val;
- if ((s->blendcon & FIMD_ALPHA_8BIT) != (old_value & FIMD_ALPHA_8BIT)) {
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- fimd_update_get_alpha(s, w);
- }
- }
- break;
- case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
- s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon = val;
- break;
- case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
- s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2] = val;
- break;
- case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
- if (offset & 0x0004) {
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
- break;
- }
- w = (offset - FIMD_VIDW0ADD0_B2) >> 3;
- if (fimd_get_buffer_id(&s->window[w]) == 2 &&
- s->window[w].buf_start[2] != val) {
- s->window[w].buf_start[2] = val;
- fimd_update_memory_section(s, w);
- break;
- }
- s->window[w].buf_start[2] = val;
- break;
- case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
- if (offset & 0x0004) {
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
- break;
- }
- s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val;
- break;
- case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
- if (offset & 0x0004) {
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
- break;
- }
- s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val;
- break;
- case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
- s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size = val;
- break;
- case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
- w = (offset - FIMD_PAL_MEM_START) >> 10;
- i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
- s->window[w].palette[i] = val;
- break;
- case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
- /* Palette memory aliases for windows 0 and 1 */
- w = (offset - FIMD_PALMEM_AL_START) >> 10;
- i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
- s->window[w].palette[i] = val;
- break;
- default:
- DPRINT_ERROR("bad write offset 0x%08x\n", offset);
- break;
- }
-}
-
-static uint64_t exynos4210_fimd_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- int w, i;
- uint32_t ret = 0;
-
- DPRINT_L2("read offset 0x%08x\n", offset);
-
- switch (offset) {
- case FIMD_VIDCON0 ... FIMD_VIDCON3:
- return s->vidcon[(offset - FIMD_VIDCON0) >> 2];
- case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
- return s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2];
- case FIMD_WINCON_START ... FIMD_WINCON_END:
- return s->window[(offset - FIMD_WINCON_START) >> 2].wincon;
- case FIMD_SHADOWCON:
- return s->shadowcon;
- case FIMD_WINCHMAP:
- return s->winchmap;
- case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
- w = (offset - FIMD_VIDOSD_START) >> 4;
- i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
- switch (i) {
- case 0:
- ret = ((s->window[w].lefttop_x & FIMD_VIDOSD_COORD_MASK) <<
- FIMD_VIDOSD_HOR_SHIFT) |
- (s->window[w].lefttop_y & FIMD_VIDOSD_COORD_MASK);
- break;
- case 1:
- ret = ((s->window[w].rightbot_x & FIMD_VIDOSD_COORD_MASK) <<
- FIMD_VIDOSD_HOR_SHIFT) |
- (s->window[w].rightbot_y & FIMD_VIDOSD_COORD_MASK);
- break;
- case 2:
- if (w == 0) {
- ret = s->window[w].osdsize;
- } else {
- ret = (pack_upper_4(s->window[w].alpha_val[0]) <<
- FIMD_VIDOSD_AEN0_SHIFT) |
- pack_upper_4(s->window[w].alpha_val[1]);
- }
- break;
- case 3:
- if (w != 1 && w != 2) {
- DPRINT_ERROR("bad read offset 0x%08x\n", offset);
- return 0xBAADBAAD;
- }
- ret = s->window[w].osdsize;
- break;
- }
- return ret;
- case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
- w = (offset - FIMD_VIDWADD0_START) >> 3;
- i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
- return s->window[w].buf_start[i];
- case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
- w = (offset - FIMD_VIDWADD1_START) >> 3;
- i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
- return s->window[w].buf_end[i];
- case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
- w = (offset - FIMD_VIDWADD2_START) >> 2;
- return s->window[w].virtpage_width | (s->window[w].virtpage_offsize <<
- FIMD_VIDWADD2_OFFSIZE_SHIFT);
- case FIMD_VIDINTCON0 ... FIMD_VIDINTCON1:
- return s->vidintcon[(offset - FIMD_VIDINTCON0) >> 2];
- case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
- w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
- i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
- return s->window[w].keycon[i];
- case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
- w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
- return s->window[w].keyalpha;
- case FIMD_DITHMODE:
- return s->dithmode;
- case FIMD_WINMAP_START ... FIMD_WINMAP_END:
- return s->window[(offset - FIMD_WINMAP_START) >> 2].winmap;
- case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
- return s->wpalcon[(offset - FIMD_WPALCON_HIGH) >> 2];
- case FIMD_TRIGCON:
- return s->trigcon;
- case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
- return s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2];
- case FIMD_COLORGAINCON:
- return s->colorgaincon;
- case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
- return s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2];
- case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
- i = (offset - FIMD_SIFCCON0) >> 2;
- return s->sifccon[i];
- case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
- i = (offset - FIMD_HUECOEFCR_START) >> 2;
- return s->huecoef_cr[i];
- case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
- i = (offset - FIMD_HUECOEFCB_START) >> 2;
- return s->huecoef_cb[i];
- case FIMD_HUEOFFSET:
- return s->hueoffset;
- case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
- w = ((offset - FIMD_VIDWALPHA_START) >> 3);
- i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
- return s->window[w].alpha_val[i] &
- (w == 0 ? 0xFFFFFF : FIMD_VIDALPHA_ALPHA_LOWER);
- case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
- return s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq;
- case FIMD_BLENDCON:
- return s->blendcon;
- case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
- return s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon;
- case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
- return s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2];
- case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
- if (offset & 0x0004) {
- break;
- }
- return s->window[(offset - FIMD_VIDW0ADD0_B2) >> 3].buf_start[2];
- case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
- if (offset & 0x0004) {
- break;
- }
- return s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start;
- case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
- if (offset & 0x0004) {
- break;
- }
- return s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end;
- case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
- return s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size;
- case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
- w = (offset - FIMD_PAL_MEM_START) >> 10;
- i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
- return s->window[w].palette[i];
- case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
- /* Palette aliases for win 0,1 */
- w = (offset - FIMD_PALMEM_AL_START) >> 10;
- i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
- return s->window[w].palette[i];
- }
-
- DPRINT_ERROR("bad read offset 0x%08x\n", offset);
- return 0xBAADBAAD;
-}
-
-static const MemoryRegionOps exynos4210_fimd_mmio_ops = {
- .read = exynos4210_fimd_read,
- .write = exynos4210_fimd_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int exynos4210_fimd_load(void *opaque, int version_id)
-{
- Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
- int w;
-
- if (version_id != 1) {
- return -EINVAL;
- }
-
- for (w = 0; w < NUM_OF_WINDOWS; w++) {
- exynos4210_fimd_update_win_bppmode(s, w);
- fimd_update_get_alpha(s, w);
- fimd_update_memory_section(s, w);
- }
-
- /* Redraw the whole screen */
- exynos4210_update_resolution(s);
- exynos4210_fimd_invalidate(s);
- exynos4210_fimd_enable(s, (s->vidcon[0] & FIMD_VIDCON0_ENVID_MASK) ==
- FIMD_VIDCON0_ENVID_MASK);
- return 0;
-}
-
-static const VMStateDescription exynos4210_fimd_window_vmstate = {
- .name = "exynos4210.fimd_window",
- .version_id = 1,
- .minimum_version_id = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(wincon, Exynos4210fimdWindow),
- VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3),
- VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3),
- VMSTATE_UINT32_ARRAY(keycon, Exynos4210fimdWindow, 2),
- VMSTATE_UINT32(keyalpha, Exynos4210fimdWindow),
- VMSTATE_UINT32(winmap, Exynos4210fimdWindow),
- VMSTATE_UINT32(blendeq, Exynos4210fimdWindow),
- VMSTATE_UINT32(rtqoscon, Exynos4210fimdWindow),
- VMSTATE_UINT32_ARRAY(palette, Exynos4210fimdWindow, 256),
- VMSTATE_UINT32(shadow_buf_start, Exynos4210fimdWindow),
- VMSTATE_UINT32(shadow_buf_end, Exynos4210fimdWindow),
- VMSTATE_UINT32(shadow_buf_size, Exynos4210fimdWindow),
- VMSTATE_UINT16(lefttop_x, Exynos4210fimdWindow),
- VMSTATE_UINT16(lefttop_y, Exynos4210fimdWindow),
- VMSTATE_UINT16(rightbot_x, Exynos4210fimdWindow),
- VMSTATE_UINT16(rightbot_y, Exynos4210fimdWindow),
- VMSTATE_UINT32(osdsize, Exynos4210fimdWindow),
- VMSTATE_UINT32_ARRAY(alpha_val, Exynos4210fimdWindow, 2),
- VMSTATE_UINT16(virtpage_width, Exynos4210fimdWindow),
- VMSTATE_UINT16(virtpage_offsize, Exynos4210fimdWindow),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription exynos4210_fimd_vmstate = {
- .name = "exynos4210.fimd",
- .version_id = 1,
- .minimum_version_id = 1,
- .post_load = exynos4210_fimd_load,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4),
- VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4),
- VMSTATE_UINT32(shadowcon, Exynos4210fimdState),
- VMSTATE_UINT32(winchmap, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(vidintcon, Exynos4210fimdState, 2),
- VMSTATE_UINT32(dithmode, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(wpalcon, Exynos4210fimdState, 2),
- VMSTATE_UINT32(trigcon, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(i80ifcon, Exynos4210fimdState, 4),
- VMSTATE_UINT32(colorgaincon, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(ldi_cmdcon, Exynos4210fimdState, 2),
- VMSTATE_UINT32_ARRAY(sifccon, Exynos4210fimdState, 3),
- VMSTATE_UINT32_ARRAY(huecoef_cr, Exynos4210fimdState, 4),
- VMSTATE_UINT32_ARRAY(huecoef_cb, Exynos4210fimdState, 4),
- VMSTATE_UINT32(hueoffset, Exynos4210fimdState),
- VMSTATE_UINT32_ARRAY(i80ifcmd, Exynos4210fimdState, 12),
- VMSTATE_UINT32(blendcon, Exynos4210fimdState),
- VMSTATE_STRUCT_ARRAY(window, Exynos4210fimdState, 5, 1,
- exynos4210_fimd_window_vmstate, Exynos4210fimdWindow),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static int exynos4210_fimd_init(SysBusDevice *dev)
-{
- Exynos4210fimdState *s = FROM_SYSBUS(Exynos4210fimdState, dev);
-
- s->ifb = NULL;
-
- sysbus_init_irq(dev, &s->irq[0]);
- sysbus_init_irq(dev, &s->irq[1]);
- sysbus_init_irq(dev, &s->irq[2]);
-
- memory_region_init_io(&s->iomem, &exynos4210_fimd_mmio_ops, s,
- "exynos4210.fimd", FIMD_REGS_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
- s->console = graphic_console_init(exynos4210_fimd_update,
- exynos4210_fimd_invalidate, NULL, NULL, s);
-
- return 0;
-}
-
-static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- dc->vmsd = &exynos4210_fimd_vmstate;
- dc->reset = exynos4210_fimd_reset;
- k->init = exynos4210_fimd_init;
-}
-
-static TypeInfo exynos4210_fimd_info = {
- .name = "exynos4210.fimd",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210fimdState),
- .class_init = exynos4210_fimd_class_init,
-};
-
-static void exynos4210_fimd_register_types(void)
-{
- type_register_static(&exynos4210_fimd_info);
-}
-
-type_init(exynos4210_fimd_register_types)
+++ /dev/null
-/*
- * Samsung exynos4210 MALI400 gpu (G3D) emulation
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Mitsyanko Igor <i.mitsyanko@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "qemu-common.h"
-#include "sysbus.h"
-
-/* Debug messages configuration */
-#define EXY_G3D_DEBUG 0
-
-#if EXY_G3D_DEBUG == 0
- #define DPRINT_L1(fmt, args...) do { } while (0)
- #define DPRINT_L2(fmt, args...) do { } while (0)
- #define DPRINT_ERROR(fmt, args...) do { } while (0)
-#elif EXY_G3D_DEBUG == 1
- #define DPRINT_L1(fmt, args...) \
- do {fprintf(stderr, "QEMU G3D: "fmt, ## args); } while (0)
- #define DPRINT_L2(fmt, args...) do { } while (0)
- #define DPRINT_ERROR(fmt, args...) \
- do {fprintf(stderr, "QEMU G3D ERROR: "fmt, ## args); } while (0)
-#else
- #define DPRINT_L1(fmt, args...) \
- do {fprintf(stderr, "QEMU G3D: "fmt, ## args); } while (0)
- #define DPRINT_L2(fmt, args...) \
- do {fprintf(stderr, "QEMU G3D: "fmt, ## args); } while (0)
- #define DPRINT_ERROR(fmt, args...) \
- do {fprintf(stderr, "QEMU G3D ERROR: "fmt, ## args); } while (0)
-#endif
-
-#define NUM_OF_PIXPROC 4
-#define EXYNOS4210_G3D_REG_MEM_SIZE 0x10000
-#define MALIGP_REGS_SIZE 0x98
-#define MALIPP_REGS_SIZE 0x10f0
-#define MALIMMU_REGS_SIZE 0x24
-#define MALI_L2CACHE_REGS_SIZE 0x30
-
-#define GP_OFF_START 0x0000
-#define GP_OFF_END (GP_OFF_START + MALIGP_REGS_SIZE)
-#define L2_OFF_START 0x1000
-#define L2_OFF_END (L2_OFF_START + MALI_L2CACHE_REGS_SIZE)
-#define PMU_OFF_START 0x2000
-#define PMU_OFF_END 0x2FFC
-#define GP_MMU_OFF_START 0x3000
-#define GP_MMU_OFF_END (GP_MMU_OFF_START + MALIMMU_REGS_SIZE)
-#define PP0_MMU_OFF_START 0x4000
-#define PP0_MMU_OFF_END (PP0_MMU_OFF_START + MALIMMU_REGS_SIZE)
-#define PP1_MMU_OFF_START 0x5000
-#define PP1_MMU_OFF_END (PP1_MMU_OFF_START + MALIMMU_REGS_SIZE)
-#define PP2_MMU_OFF_START 0x6000
-#define PP2_MMU_OFF_END (PP2_MMU_OFF_START + MALIMMU_REGS_SIZE)
-#define PP3_MMU_OFF_START 0x7000
-#define PP3_MMU_OFF_END (PP3_MMU_OFF_START + MALIMMU_REGS_SIZE)
-#define PP0_OFF_START 0x8000
-#define PP0_OFF_END (PP0_OFF_START + MALIPP_REGS_SIZE)
-#define PP1_OFF_START 0xA000
-#define PP1_OFF_END (PP1_OFF_START + MALIPP_REGS_SIZE)
-#define PP2_OFF_START 0xC000
-#define PP2_OFF_END (PP2_OFF_START + MALIPP_REGS_SIZE)
-#define PP3_OFF_START 0xE000
-#define PP3_OFF_END (PP3_OFF_START + MALIPP_REGS_SIZE)
-
-/**************************************************
- * MALI geometry processor register defines
- **************************************************/
-
-#define MALIGP_REG_OFF_VSCL_START_ADDR 0x00
-#define MALIGP_REG_OFF_VSCL_END_ADDR 0x04
-#define MALIGP_REG_OFF_PLBUCL_START_ADDR 0x08
-#define MALIGP_REG_OFF_PLBUCL_END_ADDR 0x0c
-#define MALIGP_REG_OFF_PLBU_ALLOC_START_ADDR 0x10
-#define MALIGP_REG_OFF_PLBU_ALLOC_END_ADDR 0x14
-
-/* Command to geometry processor */
-#define MALIGP_REG_OFF_CMD 0x20
-#define MALIGP_REG_VAL_CMD_START_VS (1 << 0)
-#define MALIGP_REG_VAL_CMD_START_PLBU (1 << 1)
-#define MALIGP_REG_VAL_CMD_UPDATE_PLBU_ALLOC (1 << 4)
-#define MALIGP_REG_VAL_CMD_RESET (1 << 5)
-#define MALIGP_REG_VAL_CMD_FORCE_HANG (1 << 6)
-#define MALIGP_REG_VAL_CMD_STOP_BUS (1 << 9)
-#define MALIGP_REG_VAL_CMD_SOFT_RESET (1 << 10)
-
-/* Raw interrupt ststus - can not be masked by INT_MASK */
-#define MALIGP_REG_OFF_INT_RAWSTAT 0x24
-/* WO register - write 1 to clear irq flag in INT_RAWSTAT */
-#define MALIGP_REG_OFF_INT_CLEAR 0x28
-/* MASK interrupt requests in IRQ_STATUS */
-#define MALIGP_REG_OFF_INT_MASK 0x2C
-/* Bits are set only if not masked and if bit in RAWSTAT is set */
-#define MALIGP_REG_OFF_INT_STAT 0x30
-/* Interrupt statuses of geometry processor */
-#define MALIGP_REG_VAL_IRQ_VS_END_CMD_LST (1 << 0)
-#define MALIGP_REG_VAL_IRQ_PLBU_END_CMD_LST (1 << 1)
-#define MALIGP_REG_VAL_IRQ_PLBU_OUT_OF_MEM (1 << 2)
-#define MALIGP_REG_VAL_IRQ_VS_SEM_IRQ (1 << 3)
-#define MALIGP_REG_VAL_IRQ_PLBU_SEM_IRQ (1 << 4)
-#define MALIGP_REG_VAL_IRQ_HANG (1 << 5)
-#define MALIGP_REG_VAL_IRQ_FORCE_HANG (1 << 6)
-#define MALIGP_REG_VAL_IRQ_PERF_CNT_0_LIMIT (1 << 7)
-#define MALIGP_REG_VAL_IRQ_PERF_CNT_1_LIMIT (1 << 8)
-#define MALIGP_REG_VAL_IRQ_WRITE_BOUND_ERR (1 << 9)
-#define MALIGP_REG_VAL_IRQ_SYNC_ERROR (1 << 10)
-#define MALIGP_REG_VAL_IRQ_AXI_BUS_ERROR (1 << 11)
-#define MALIGP_REG_VAL_IRQ_AXI_BUS_STOPPED (1 << 12)
-#define MALIGP_REG_VAL_IRQ_VS_INVALID_CMD (1 << 13)
-#define MALIGP_REG_VAL_IRQ_PLB_INVALID_CMD (1 << 14)
-#define MALIGP_REG_VAL_IRQ_RESET_COMPLETED (1 << 19)
-#define MALIGP_REG_VAL_IRQ_SEMAPHORE_UNDERFLOW (1 << 20)
-#define MALIGP_REG_VAL_IRQ_SEMAPHORE_OVERFLOW (1 << 21)
-#define MALIGP_REG_VAL_IRQ_PTR_ARRAY_OUT_OF_BOUNDS (1 << 22)
-#define MALIGP_REG_VAL_IRQ_MASK_ALL \
- (\
- MALIGP_REG_VAL_IRQ_VS_END_CMD_LST | \
- MALIGP_REG_VAL_IRQ_PLBU_END_CMD_LST | \
- MALIGP_REG_VAL_IRQ_PLBU_OUT_OF_MEM | \
- MALIGP_REG_VAL_IRQ_VS_SEM_IRQ | \
- MALIGP_REG_VAL_IRQ_PLBU_SEM_IRQ | \
- MALIGP_REG_VAL_IRQ_HANG | \
- MALIGP_REG_VAL_IRQ_FORCE_HANG | \
- MALIGP_REG_VAL_IRQ_PERF_CNT_0_LIMIT | \
- MALIGP_REG_VAL_IRQ_PERF_CNT_1_LIMIT | \
- MALIGP_REG_VAL_IRQ_WRITE_BOUND_ERR | \
- MALIGP_REG_VAL_IRQ_SYNC_ERROR | \
- MALIGP_REG_VAL_IRQ_AXI_BUS_ERROR | \
- MALIGP_REG_VAL_IRQ_AXI_BUS_STOPPED | \
- MALIGP_REG_VAL_IRQ_VS_INVALID_CMD | \
- MALIGP_REG_VAL_IRQ_PLB_INVALID_CMD | \
- MALIGP_REG_VAL_IRQ_RESET_COMPLETED | \
- MALIGP_REG_VAL_IRQ_SEMAPHORE_UNDERFLOW | \
- MALIGP_REG_VAL_IRQ_SEMAPHORE_OVERFLOW | \
- MALIGP_REG_VAL_IRQ_PTR_ARRAY_OUT_OF_BOUNDS)
-
-
-#define MALIGP_REG_OFF_WRITE_BOUND_LOW 0x34
-#define MALIGP_REG_OFF_PERF_CNT_0_ENABLE 0x3C
-#define MALIGP_REG_OFF_PERF_CNT_1_ENABLE 0x40
-#define MALIGP_REG_OFF_PERF_CNT_0_SRC 0x44
-#define MALIGP_REG_OFF_PERF_CNT_1_SRC 0x48
-#define MALIGP_REG_OFF_PERF_CNT_0_VALUE 0x4C
-#define MALIGP_REG_OFF_PERF_CNT_1_VALUE 0x50
-#define MALIGP_REG_OFF_STATUS 0x68
-
-/* Geometry processor version register */
-#define MALIGP_REG_OFF_VERSION 0x6C
-#define MALI400_GP_PRODUCT_ID 0xB07
-#define MALIGP_VERSION_DEFAULT (MALI400_GP_PRODUCT_ID << 16)
-
-#define MALIGP_REG_OFF_VSCL_START_ADDR_READ 0x80
-#define MALIGP_REG_OFF_PLBCL_START_ADDR_READ 0x84
-#define MALIGP_CONTR_AXI_BUS_ERROR_STAT 0x94
-#define MALIGP_REGISTER_ADDRESS_SPACE_SIZE 0x98
-
-
-/**************************************************
- * MALI pixel processor registers defines
- **************************************************/
-
-/* MALI Pixel Processor version register */
-#define MALIPP_REG_OFF_VERSION 0x1000
-#define MALI400_PP_PRODUCT_ID 0xCD07
-#define MALIPP_MGMT_VERSION_DEFAULT (MALI400_PP_PRODUCT_ID << 16)
-
-#define MALIPP_REG_OFF_CURRENT_REND_LIST_ADDR 0x1004
-#define MALIPP_REG_OFF_STATUS 0x1008
-
-/* Control and commands register */
-#define MALIPP_REG_OFF_CTRL_MGMT 0x100c
-#define MALIPP_REG_VAL_CTRL_MGMT_STOP_BUS (1 << 0)
-#define MALIPP_REG_VAL_CTRL_MGMT_FORCE_RESET (1 << 5)
-#define MALIPP_REG_VAL_CTRL_MGMT_START_RENDERING (1 << 6)
-#define MALIPP_REG_VAL_CTRL_MGMT_SOFT_RESET (1 << 7)
-
-/* Interrupt control registers */
-#define MALIPP_REG_OFF_INT_RAWSTAT 0x1020
-#define MALIPP_REG_OFF_INT_CLEAR 0x1024
-#define MALIPP_REG_OFF_INT_MASK 0x1028
-#define MALIPP_REG_OFF_INT_STATUS 0x102c
-/* Interrupt statuses */
-#define MALIPP_REG_VAL_IRQ_END_OF_FRAME (1 << 0)
-#define MALIPP_REG_VAL_IRQ_END_OF_TILE (1 << 1)
-#define MALIPP_REG_VAL_IRQ_HANG (1 << 2)
-#define MALIPP_REG_VAL_IRQ_FORCE_HANG (1 << 3)
-#define MALIPP_REG_VAL_IRQ_BUS_ERROR (1 << 4)
-#define MALIPP_REG_VAL_IRQ_BUS_STOP (1 << 5)
-#define MALIPP_REG_VAL_IRQ_CNT_0_LIMIT (1 << 6)
-#define MALIPP_REG_VAL_IRQ_CNT_1_LIMIT (1 << 7)
-#define MALIPP_REG_VAL_IRQ_WRITE_BOUNDARY_ERROR (1 << 8)
-#define MALIPP_REG_VAL_IRQ_INVALID_PLIST_COMMAND (1 << 9)
-#define MALIPP_REG_VAL_IRQ_CALL_STACK_UNDERFLOW (1 << 10)
-#define MALIPP_REG_VAL_IRQ_CALL_STACK_OVERFLOW (1 << 11)
-#define MALIPP_REG_VAL_IRQ_RESET_COMPLETED (1 << 12)
-
-
-#define MALIPP_REG_OFF_WRITE_BOUNDARY_LOW 0x1044
-#define MALIPP_REG_OFF_BUS_ERROR_STATUS 0x1050
-#define MALIPP_REG_OFF_PERF_CNT_0_ENABLE 0x1080
-#define MALIPP_REG_OFF_PERF_CNT_0_SRC 0x1084
-#define MALIPP_REG_OFF_PERF_CNT_0_VALUE 0x108c
-#define MALIPP_REG_OFF_PERF_CNT_1_ENABLE 0x10a0
-#define MALIPP_REG_OFF_PERF_CNT_1_SRC 0x10a4
-#define MALIPP_REG_OFF_PERF_CNT_1_VALUE 0x10ac
-#define MALIPP_REG_SIZEOF_REGISTER_BANK 0x10f0
-
-/**************************************************
- * MALI MMU register defines
- **************************************************/
-
-/* Current Page Directory Pointer */
-#define MALI_MMU_REG_DTE_ADDR 0x0000
-
-/* Status of the MMU */
-#define MALI_MMU_REG_STATUS 0x0004
-/* MALI MMU ststus bits */
-#define MALI_MMU_STATUS_PAGING_ENABLED (1 << 0)
-#define MALI_MMU_STATUS_PAGE_FAULT_ACTIVE (1 << 1)
-#define MALI_MMU_STATUS_STALL_ACTIVE (1 << 2)
-#define MALI_MMU_STATUS_IDLE (1 << 3)
-#define MALI_MMU_STATUS_REPLAY_BUFFER_EMPTY (1 << 4)
-#define MALI_MMU_STATUS_PAGE_FAULT_IS_WRITE (1 << 5)
-
-/* Command register, used to control the MMU */
-#define MALI_MMU_REG_COMMAND 0x0008
-/* MALI MMU commands */
-/* Enable paging (memory translation) */
-#define MALI_MMU_COMMAND_ENABLE_PAGING 0x00
-/* Disable paging (memory translation) */
-#define MALI_MMU_COMMAND_DISABLE_PAGING 0x01
-/* Enable stall on page fault */
-#define MALI_MMU_COMMAND_ENABLE_STALL 0x02
-/* Disable stall on page fault */
-#define MALI_MMU_COMMAND_DISABLE_STALL 0x03
-/* Zap the entire page table cache */
-#define MALI_MMU_COMMAND_ZAP_CACHE 0x04
-/* Page fault processed */
-#define MALI_MMU_COMMAND_PAGE_FAULT_DONE 0x05
-/* Reset the MMU back to power-on settings */
-#define MALI_MMU_COMMAND_SOFT_RESET 0x06
-
-/* Logical address of the last page fault */
-#define MALI_MMU_REG_PAGE_FAULT_ADDR 0x000C
-
-/* Used to invalidate the mapping of a single page from the MMU */
-#define MALI_MMU_REG_ZAP_ONE_LINE 0x0010
-
-/* Raw interrupt status, all interrupts visible */
-#define MALI_MMU_REG_INT_RAWSTAT 0x0014
-/* Indicate to the MMU that the interrupt has been received */
-#define MALI_MMU_REG_INT_CLEAR 0x0018
-/* Enable/disable types of interrupts */
-#define MALI_MMU_REG_INT_MASK 0x001C
-/* Interrupt status based on the mask */
-#define MALI_MMU_REG_INT_STATUS 0x0020
-/* MALI MMU interrupt registers bits */
-/* A page fault occured */
-#define MALI_MMU_INT_PAGE_FAULT 0x01
-/* A bus read error occured */
-#define MALI_MMU_INT_READ_BUS_ERROR 0x02
-
-
-/**************************************************
- * MALI L2 cache register defines
- **************************************************/
-
-/* MALI L2 cache status bits */
-#define MALI_L2CACHE_REG_STATUS 0x0008
-/* Command handler of L2 cache is busy */
-#define MALI_L2CACHE_STATUS_COMMAND_BUSY 0x01
-/* L2 cache is busy handling data requests */
-#define MALI_L2CACHE_STATUS_DATA_BUSY 0x02
-
-/* Misc cache commands, e.g. clear */
-#define MALI_L2CACHE_REG_COMMAND 0x0010
-/* Clear the entire cache */
-#define MALI_L2CACHE_CMD_CLEAR_ALL 0x01
-
-#define MALI_L2CACHE_REG_CLEAR_PAGE 0x0014
-
-/* Enable misc cache features */
-#define MALI_L2CACHE_REG_ENABLE 0x001C
-/* Default state of enable register */
-#define MALI_L2CACHE_ENABLE_DEFAULT 0x0
-/* Permit cacheable accesses */
-#define MALI_L2CACHE_ENABLE_ACCESS 0x01
-/* Permit cache read allocate */
-#define MALI_L2CACHE_ENABLE_READ_ALLOCATE 0x02
-
-#define MALI_L2CACHE_REG_PERFCNT_SRC0 0x0020
-#define MALI_L2CACHE_REG_PERFCNT_VAL0 0x0024
-#define MALI_L2CACHE_REG_PERFCNT_SRC1 0x0028
-#define MALI_L2CACHE_REG_PERFCNT_VAL1 0x002C
-
-typedef struct GeometryProc {
- uint32_t vscl_start;
- uint32_t vscl_end;
- uint32_t plbucl_start;
- uint32_t plbucl_end;
- uint32_t plbu_alloc_start;
- uint32_t plbu_alloc_end;
- uint32_t cmd;
- uint32_t int_rawstat;
-/* uint32_t int_clear; Write only register */
- uint32_t int_mask;
- uint32_t int_stat;
- uint32_t write_bound;
- uint32_t perfcnt0_en;
- uint32_t perfcnt1_en;
- uint32_t perfcnt0_src;
- uint32_t perfcnt1_src;
- uint32_t perfcnt0_value;
- uint32_t perfcnt1_value;
- uint32_t status;
-/* uint32_t version; RO register */
- uint32_t vscl_start_read;
- uint32_t plbcl_start_read;
- uint32_t axi_error;
- uint32_t addr_space_size;
-
- qemu_irq irq_gp; /* geometry processor interrupt */
-} GeometryProc;
-
-typedef struct PixelProc {
-/* uint32_t version; RO register */
- uint32_t cur_rend_list;
- uint32_t status;
- uint32_t ctrl_mgmt;
- uint32_t int_rawstat;
-/* uint32_t int_clear; Write only register */
- uint32_t int_mask;
- uint32_t int_stat;
- uint32_t write_bound;
- uint32_t bus_error;
- uint32_t perfcnt0_en;
- uint32_t perfcnt0_src;
- uint32_t perfcnt0_value;
- uint32_t perfcnt1_en;
- uint32_t perfcnt1_src;
- uint32_t perfcnt1_value;
- uint32_t sizeof_regs;
-
- qemu_irq irq_pp; /* pixel processor interrupt */
-} PixelProc;
-
-typedef struct MaliMMU {
- uint32_t dte_addr;
- uint32_t status;
- uint32_t command;
- uint32_t page_fault_addr;
- uint32_t zap_one_line;
- uint32_t int_rawstat;
- uint32_t int_mask;
- uint32_t int_status;
-
- qemu_irq irq_mmu; /* MALI MMU interrupt */
-} MaliMMU;
-
-typedef struct MaliL2Cache {
- uint32_t status;
- uint32_t command;
- uint32_t clear_page;
- uint32_t enable;
- uint32_t perfcnt_src0;
- uint32_t perfcnt_val0;
- uint32_t perfcnt_src1;
- uint32_t perfcnt_val1;
-} MaliL2Cache;
-
-typedef struct Exynos4210G3DState {
- SysBusDevice busdev;
- MemoryRegion iomem;
-
- GeometryProc gp; /* Geometry processor */
- PixelProc pp[NUM_OF_PIXPROC];
- MaliMMU gp_mmu;
- MaliMMU pp_mmu[NUM_OF_PIXPROC];
- MaliL2Cache l2_cache;
- qemu_irq irq_pmu; /* power unit interrupt */
-} Exynos4210G3DState;
-
-/* TODO maybe reset functions must do something else besides clearing reg-s */
-static inline void exynos4210_maligp_reset(GeometryProc *gp)
-{
- memset(gp, 0, offsetof(GeometryProc, irq_gp));
-}
-
-static inline void exynos4210_malipp_reset(PixelProc *pp)
-{
- memset(pp, 0, offsetof(PixelProc, irq_pp));
-}
-
-static inline void exynos4210_malimmu_reset(MaliMMU *mmu)
-{
- memset(mmu, 0, offsetof(MaliMMU, irq_mmu));
-}
-
-static inline void exynos4210_mali_l2cache_reset(MaliL2Cache *l2cach)
-{
- memset(l2cach, 0, sizeof(MaliL2Cache));
-}
-
-static void exynos4210_g3d_reset(DeviceState *d)
-{
- Exynos4210G3DState *s = DO_UPCAST(Exynos4210G3DState, busdev.qdev, d);
- int i;
-
- exynos4210_maligp_reset(&s->gp);
- exynos4210_malimmu_reset(&s->gp_mmu);
- exynos4210_mali_l2cache_reset(&s->l2_cache);
- for (i = 0; i < NUM_OF_PIXPROC; i++) {
- exynos4210_malipp_reset(&s->pp[i]);
- exynos4210_malimmu_reset(&s->pp_mmu[i]);
- }
-}
-
-/* Geometry processor register map read */
-static inline uint32_t exynos4210_maligp_read(GeometryProc *gp,
- target_phys_addr_t offset)
-{
- DPRINT_L2("MALI GEOMETRY PROCESSOR: read offset 0x"
- TARGET_FMT_plx "\n", offset);
-
- switch (offset) {
- /* Geometry processor */
- case MALIGP_REG_OFF_CMD:
- return gp->cmd;
- case MALIGP_REG_OFF_INT_RAWSTAT:
- return gp->int_rawstat;
- case MALIGP_REG_OFF_INT_MASK:
- return gp->int_mask;
- case MALIGP_REG_OFF_INT_STAT:
- return gp->int_stat;
- case MALIGP_REG_OFF_VERSION:
- return MALIGP_VERSION_DEFAULT;
- case MALIGP_REG_OFF_INT_CLEAR:
- DPRINT_L1("MALI GEOM PROC: read from WO register! Offset 0x"
- TARGET_FMT_plx "\n", offset);
- return 0;
- default:
- DPRINT_L1("MALI GEOM PROC: read from non-existing register! "
- "Offset 0x" TARGET_FMT_plx "\n", offset);
- return 0;
- }
-}
-
-/* Geometry processor register map write */
-static uint32_t exynos4210_malipp_read(PixelProc *pp, target_phys_addr_t offset)
-{
- DPRINT_L2("read offset 0x" TARGET_FMT_plx "\n", offset);
-
- switch (offset) {
- case MALIPP_REG_OFF_VERSION:
- return MALIPP_MGMT_VERSION_DEFAULT;
- case MALIPP_REG_OFF_CTRL_MGMT:
- return pp->ctrl_mgmt;
- case MALIPP_REG_OFF_INT_RAWSTAT:
- return pp->int_rawstat;
- case MALIPP_REG_OFF_INT_MASK:
- return pp->int_mask;
- case MALIPP_REG_OFF_INT_STATUS:
- return pp->int_stat;
- case MALIPP_REG_OFF_INT_CLEAR:
- DPRINT_L1("MALI PIX PROC: read from WO register! Offset 0x"
- TARGET_FMT_plx "\n", offset);
- return 0;
- default:
- DPRINT_L1("MALI PIX PROC: read from non-existing register! Offset 0x"
- TARGET_FMT_plx "\n", offset);
- return 0;
- }
-}
-
-/* MALI MMU register map read */
-static uint32_t exynos4210_malimmu_read(MaliMMU *mmu, target_phys_addr_t offset)
-{
- DPRINT_L2("read offset 0x" TARGET_FMT_plx "\n", offset);
-
- switch (offset) {
- case MALI_MMU_REG_DTE_ADDR:
- return mmu->dte_addr;
- case MALI_MMU_REG_COMMAND:
- return mmu->command;
- case MALI_MMU_REG_INT_RAWSTAT:
- return mmu->int_rawstat;
- case MALI_MMU_REG_INT_MASK:
- return mmu->int_mask;
- case MALI_MMU_REG_INT_STATUS:
- return mmu->int_status;
- case MALI_MMU_REG_INT_CLEAR:
- DPRINT_L1("MALI MMU: read from WO register! Offset 0x"
- TARGET_FMT_plx "\n", offset);
- return 0;
- default:
- DPRINT_L1("MALI MMU: read from non-existing register! Offset 0x"
- TARGET_FMT_plx "\n", offset);
- return 0;
- }
-}
-
-/* MALI L2 cache register map read */
-static uint32_t exynos4210_mali_l2cache_read(MaliL2Cache *cache,
- target_phys_addr_t offset)
-{
- DPRINT_L2("MALI L2 CACHE: read offset 0x"
- TARGET_FMT_plx "\n", offset);
-
- switch (offset) {
- case MALI_L2CACHE_REG_STATUS:
- return cache->status;
- case MALI_L2CACHE_REG_COMMAND:
- return cache->command;
- case MALI_L2CACHE_REG_ENABLE:
- return cache->enable;
- default:
- return 0;
- }
-}
-
-static uint64_t exynos4210_g3d_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- Exynos4210G3DState *s = (Exynos4210G3DState *)opaque;
-
- switch (offset) {
- case GP_OFF_START ... GP_OFF_END:
- return exynos4210_maligp_read(&s->gp, offset - GP_OFF_START);
- case PP0_OFF_START ... PP0_OFF_END:
- DPRINT_L2("MALI PIXEL PROCESSOR#0: ");
- return exynos4210_malipp_read(&s->pp[0], offset - PP0_OFF_START);
- case PP1_OFF_START ... PP1_OFF_END:
- DPRINT_L2("MALI PIXEL PROCESSOR#1: ");
- return exynos4210_malipp_read(&s->pp[1], offset - PP1_OFF_START);
- case PP2_OFF_START ... PP2_OFF_END:
- DPRINT_L2("MALI PIXEL PROCESSOR#2: ");
- return exynos4210_malipp_read(&s->pp[2], offset - PP2_OFF_START);
- case PP3_OFF_START ... PP3_OFF_END:
- DPRINT_L2("MALI PIXEL PROCESSOR#3: ");
- return exynos4210_malipp_read(&s->pp[3], offset - PP3_OFF_START);
- case GP_MMU_OFF_START ... GP_MMU_OFF_END:
- DPRINT_L2("MALI GEOM PROC MMU: ");
- return exynos4210_malimmu_read(&s->gp_mmu, offset - GP_MMU_OFF_START);
- case PP0_MMU_OFF_START ... PP0_MMU_OFF_END:
- DPRINT_L2("MALI PIX PROC#0 MMU: ");
- return exynos4210_malimmu_read(&s->pp_mmu[0],
- offset - PP0_MMU_OFF_START);
- case PP1_MMU_OFF_START ... PP1_MMU_OFF_END:
- DPRINT_L2("MALI PIX PROC#1 MMU: ");
- return exynos4210_malimmu_read(&s->pp_mmu[1],
- offset - PP1_MMU_OFF_START);
- case PP2_MMU_OFF_START ... PP2_MMU_OFF_END:
- DPRINT_L2("MALI PIX PROC#2 MMU: ");
- return exynos4210_malimmu_read(&s->pp_mmu[2],
- offset - PP2_MMU_OFF_START);
- case PP3_MMU_OFF_START ... PP3_MMU_OFF_END:
- DPRINT_L2("MALI PIX PROC#3 MMU: ");
- return exynos4210_malimmu_read(&s->pp_mmu[3],
- offset - PP3_MMU_OFF_START);
- case L2_OFF_START ... L2_OFF_END:
- return exynos4210_mali_l2cache_read(&s->l2_cache,
- offset - L2_OFF_START);
- default:
- DPRINT_L1("MALI UNKNOWN REGION: read offset 0x"
- TARGET_FMT_plx "\n", offset);
- return 0;
- }
-}
-
-/* Geometry processor register map write */
-static void exynos4210_maligp_write(GeometryProc *gp,
- target_phys_addr_t offset, uint32_t val)
-{
- DPRINT_L2("MALI GEOMETRY PROCESSOR: write offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
-
- switch (offset) {
- case MALIGP_REG_OFF_CMD:
- gp->cmd = val;
- if (val & MALIGP_REG_VAL_CMD_SOFT_RESET) {
- exynos4210_maligp_reset(gp);
- gp->int_rawstat |= MALIGP_REG_VAL_IRQ_RESET_COMPLETED;
- gp->int_stat = gp->int_rawstat & gp->int_mask;
- qemu_set_irq(gp->irq_gp, gp->int_stat);
- }
- break;
- case MALIGP_REG_OFF_INT_CLEAR:
- gp->int_rawstat &= ~val;
- gp->int_stat = gp->int_rawstat & gp->int_mask;
- qemu_irq_lower(gp->irq_gp);
- break;
- case MALIGP_REG_OFF_INT_MASK:
- gp->int_mask = val;
- break;
- case MALIGP_REG_OFF_VERSION: case MALIGP_REG_OFF_INT_RAWSTAT:
- case MALIGP_REG_OFF_INT_STAT:
- DPRINT_L1("MALI GEOM PROC: writing to RO register! Offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
- break;
- default:
- DPRINT_L1("MALI GEOM PROC: writing to non-existing register! "
- "Offset 0x" TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
- break;
- }
-}
-
-/* Pixel processor register map write */
-static void exynos4210_malipp_write(PixelProc *pp,
- target_phys_addr_t offset, uint32_t val)
-{
- DPRINT_L2("write offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
-
- switch (offset) {
- case MALIPP_REG_OFF_CTRL_MGMT:
- pp->ctrl_mgmt = val;
- if (val & MALIPP_REG_VAL_CTRL_MGMT_SOFT_RESET) {
- exynos4210_malipp_reset(pp);
- pp->int_rawstat |= MALIPP_REG_VAL_IRQ_RESET_COMPLETED;
- pp->int_stat = pp->int_rawstat & pp->int_mask;
- qemu_set_irq(pp->irq_pp, pp->int_stat);
- }
- break;
- case MALIPP_REG_OFF_INT_CLEAR:
- pp->int_rawstat &= ~val;
- pp->int_stat = pp->int_rawstat & pp->int_mask;
- qemu_irq_lower(pp->irq_pp);
- break;
- case MALIPP_REG_OFF_INT_MASK:
- pp->int_mask = val;
- break;
- case MALIPP_REG_OFF_INT_STATUS: case MALIPP_REG_OFF_VERSION:
- case MALIPP_REG_OFF_INT_RAWSTAT:
- DPRINT_L1("MALI PIX PROC: writing to RO register! Offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
- break;
- default:
- DPRINT_L1("MALI PIX PROC: writing to non-existing register! Offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
- break;
- }
-}
-
-/* MALI MMU register map write */
-static void exynos4210_malimmu_write(MaliMMU *mmu,
- target_phys_addr_t offset, uint32_t val)
-{
- DPRINT_L2("write offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
-
- switch (offset) {
- case MALI_MMU_REG_DTE_ADDR:
- mmu->dte_addr = val;
- break;
- case MALI_MMU_REG_COMMAND:
- mmu->command = val;
- if (val & MALI_MMU_COMMAND_SOFT_RESET) {
- exynos4210_malimmu_reset(mmu);
- }
- break;
- case MALI_MMU_REG_INT_CLEAR:
- mmu->int_rawstat &= ~val;
- mmu->int_status = mmu->int_rawstat & mmu->int_mask;
- qemu_irq_lower(mmu->irq_mmu);
- break;
- case MALI_MMU_REG_INT_MASK:
- mmu->int_mask = val;
- break;
- case MALI_MMU_REG_INT_STATUS: case MALI_MMU_REG_INT_RAWSTAT:
- DPRINT_L1("MALI MMU: writing to RO register! Offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
- break;
- default:
- DPRINT_L1("MALI MMU: writing to non-existing register! Offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
- break;
- }
-}
-
-/* MALI L2 cache register map write */
-static void exynos4210_mali_l2cache_write(MaliL2Cache *cache,
- target_phys_addr_t offset, uint32_t val)
-{
- DPRINT_L2("MALI L2 CACHE: write offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
-
- switch (offset) {
- case MALI_L2CACHE_REG_COMMAND:
- cache->command = val;
- break;
- case MALI_L2CACHE_REG_ENABLE:
- cache->enable = val;
- break;
- case MALI_L2CACHE_REG_STATUS:
- DPRINT_L1("MALI L2 CACHE: writing to RO register! Offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
- break;
- default:
- DPRINT_L1("MALI L2 CACHE: writing non-existing register! Offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
- break;
- }
-}
-
-static void exynos4210_g3d_write(void *opaque, target_phys_addr_t offset,
- uint64_t val, unsigned size)
-{
- Exynos4210G3DState *s = (Exynos4210G3DState *)opaque;
-
- switch (offset) {
- case GP_OFF_START ... GP_OFF_END:
- exynos4210_maligp_write(&s->gp, offset - GP_OFF_START, val);
- break;
- case PP0_OFF_START ... PP0_OFF_END:
- DPRINT_L2("MALI PIXEL PROCESSOR#0: ");
- exynos4210_malipp_write(&s->pp[0], offset - PP0_OFF_START, val);
- break;
- case PP1_OFF_START ... PP1_OFF_END:
- DPRINT_L2("MALI PIXEL PROCESSOR#1: ");
- exynos4210_malipp_write(&s->pp[1], offset - PP1_OFF_START, val);
- break;
- case PP2_OFF_START ... PP2_OFF_END:
- DPRINT_L2("MALI PIXEL PROCESSOR#2: ");
- exynos4210_malipp_write(&s->pp[2], offset - PP2_OFF_START, val);
- break;
- case PP3_OFF_START ... PP3_OFF_END:
- DPRINT_L2("MALI PIXEL PROCESSOR#3: ");
- exynos4210_malipp_write(&s->pp[3], offset - PP3_OFF_START, val);
- break;
- case GP_MMU_OFF_START ... GP_MMU_OFF_END:
- DPRINT_L2("MALI GEOM PROC MMU: ");
- exynos4210_malimmu_write(&s->gp_mmu, offset - GP_MMU_OFF_START, val);
- break;
- case PP0_MMU_OFF_START ... PP0_MMU_OFF_END:
- DPRINT_L2("MALI PIX PROC#0 MMU: ");
- exynos4210_malimmu_write(&s->pp_mmu[0],
- offset - PP0_MMU_OFF_START, val);
- break;
- case PP1_MMU_OFF_START ... PP1_MMU_OFF_END:
- DPRINT_L2("MALI PIX PROC#1 MMU: ");
- exynos4210_malimmu_write(&s->pp_mmu[1],
- offset - PP1_MMU_OFF_START, val);
- break;
- case PP2_MMU_OFF_START ... PP2_MMU_OFF_END:
- DPRINT_L2("MALI PIX PROC#2 MMU: ");
- exynos4210_malimmu_write(&s->pp_mmu[2],
- offset - PP2_MMU_OFF_START, val);
- break;
- case PP3_MMU_OFF_START ... PP3_MMU_OFF_END:
- DPRINT_L2("MALI PIX PROC#3 MMU: ");
- exynos4210_malimmu_write(&s->pp_mmu[3],
- offset - PP3_MMU_OFF_START, val);
- break;
- case L2_OFF_START ... L2_OFF_END:
- exynos4210_mali_l2cache_write(&s->l2_cache, offset - L2_OFF_START, val);
- break;
- default:
- DPRINT_L1("MALI UNKNOWN REGION: write offset 0x"
- TARGET_FMT_plx ", value=%d(0x%x) \n", offset, val, val);
- break;
- }
-}
-
-static const MemoryRegionOps exynos4210_g3d_mmio_ops = {
- .read = exynos4210_g3d_read,
- .write = exynos4210_g3d_write,
- .valid = {
- .min_access_size = 4,
- .max_access_size = 4,
- .unaligned = false
- },
- .endianness = DEVICE_NATIVE_ENDIAN,
-};
-
-static int exynos4210_g3d_init(SysBusDevice *dev)
-{
- Exynos4210G3DState *s = FROM_SYSBUS(Exynos4210G3DState, dev);
-
- sysbus_init_irq(dev, &s->pp[0].irq_pp);
- sysbus_init_irq(dev, &s->pp[1].irq_pp);
- sysbus_init_irq(dev, &s->pp[2].irq_pp);
- sysbus_init_irq(dev, &s->pp[3].irq_pp);
- sysbus_init_irq(dev, &s->gp.irq_gp);
- sysbus_init_irq(dev, &s->irq_pmu);
- sysbus_init_irq(dev, &s->pp_mmu[0].irq_mmu);
- sysbus_init_irq(dev, &s->pp_mmu[1].irq_mmu);
- sysbus_init_irq(dev, &s->pp_mmu[2].irq_mmu);
- sysbus_init_irq(dev, &s->pp_mmu[3].irq_mmu);
- sysbus_init_irq(dev, &s->gp_mmu.irq_mmu);
-
- memory_region_init_io(&s->iomem, &exynos4210_g3d_mmio_ops, s,
- "exynos4210.g3d", EXYNOS4210_G3D_REG_MEM_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-
- return 0;
-}
-
-static void exynos4210_g3d_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- dc->reset = exynos4210_g3d_reset;
- k->init = exynos4210_g3d_init;
-}
-
-static TypeInfo exynos4210_g3d_info = {
- .name = "exynos4210.g3d",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210G3DState),
- .class_init = exynos4210_g3d_class_init,
-};
-
-static void exynos4210_g3d_register_devices(void)
-{
- type_register_static(&exynos4210_g3d_info);
-}
-
-type_init(exynos4210_g3d_register_devices)
+++ /dev/null
-/*
- * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c
- *
- * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
- * All rights reserved.
- *
- * Evgeny Voevodin <e.voevodin@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or (at your
- * option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
- * See the GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- */
-
-#include "sysbus.h"
-#include "qemu-common.h"
-#include "irq.h"
-#include "exynos4210.h"
-
-enum ExtGicId {
- EXT_GIC_ID_MDMA_LCD0 = 66,
- EXT_GIC_ID_PDMA0,
- EXT_GIC_ID_PDMA1,
- EXT_GIC_ID_TIMER0,
- EXT_GIC_ID_TIMER1,
- EXT_GIC_ID_TIMER2,
- EXT_GIC_ID_TIMER3,
- EXT_GIC_ID_TIMER4,
- EXT_GIC_ID_MCT_L0,
- EXT_GIC_ID_WDT,
- EXT_GIC_ID_RTC_ALARM,
- EXT_GIC_ID_RTC_TIC,
- EXT_GIC_ID_GPIO_XB,
- EXT_GIC_ID_GPIO_XA,
- EXT_GIC_ID_MCT_L1,
- EXT_GIC_ID_IEM_APC,
- EXT_GIC_ID_IEM_IEC,
- EXT_GIC_ID_NFC,
- EXT_GIC_ID_UART0,
- EXT_GIC_ID_UART1,
- EXT_GIC_ID_UART2,
- EXT_GIC_ID_UART3,
- EXT_GIC_ID_UART4,
- EXT_GIC_ID_MCT_G0,
- EXT_GIC_ID_I2C0,
- EXT_GIC_ID_I2C1,
- EXT_GIC_ID_I2C2,
- EXT_GIC_ID_I2C3,
- EXT_GIC_ID_I2C4,
- EXT_GIC_ID_I2C5,
- EXT_GIC_ID_I2C6,
- EXT_GIC_ID_I2C7,
- EXT_GIC_ID_SPI0,
- EXT_GIC_ID_SPI1,
- EXT_GIC_ID_SPI2,
- EXT_GIC_ID_MCT_G1,
- EXT_GIC_ID_USB_HOST,
- EXT_GIC_ID_USB_DEVICE,
- EXT_GIC_ID_MODEMIF,
- EXT_GIC_ID_HSMMC0,
- EXT_GIC_ID_HSMMC1,
- EXT_GIC_ID_HSMMC2,
- EXT_GIC_ID_HSMMC3,
- EXT_GIC_ID_SDMMC,
- EXT_GIC_ID_MIPI_CSI_4LANE,
- EXT_GIC_ID_MIPI_DSI_4LANE,
- EXT_GIC_ID_MIPI_CSI_2LANE,
- EXT_GIC_ID_MIPI_DSI_2LANE,
- EXT_GIC_ID_ONENAND_AUDI,
- EXT_GIC_ID_ROTATOR,
- EXT_GIC_ID_FIMC0,
- EXT_GIC_ID_FIMC1,
- EXT_GIC_ID_FIMC2,
- EXT_GIC_ID_FIMC3,
- EXT_GIC_ID_JPEG,
- EXT_GIC_ID_2D,
- EXT_GIC_ID_PCIe,
- EXT_GIC_ID_MIXER,
- EXT_GIC_ID_HDMI,
- EXT_GIC_ID_HDMI_I2C,
- EXT_GIC_ID_MFC,
- EXT_GIC_ID_TVENC,
-};
-
-enum ExtInt {
- EXT_GIC_ID_EXTINT0 = 48,
- EXT_GIC_ID_EXTINT1,
- EXT_GIC_ID_EXTINT2,
- EXT_GIC_ID_EXTINT3,
- EXT_GIC_ID_EXTINT4,
- EXT_GIC_ID_EXTINT5,
- EXT_GIC_ID_EXTINT6,
- EXT_GIC_ID_EXTINT7,
- EXT_GIC_ID_EXTINT8,
- EXT_GIC_ID_EXTINT9,
- EXT_GIC_ID_EXTINT10,
- EXT_GIC_ID_EXTINT11,
- EXT_GIC_ID_EXTINT12,
- EXT_GIC_ID_EXTINT13,
- EXT_GIC_ID_EXTINT14,
- EXT_GIC_ID_EXTINT15,
- EXT_GIC_ID_EXTINT16_31,
-};
-
-/*
- * External GIC sources which are not from External Interrupt Combiner or
- * External Interrupts are starting from EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ,
- * which is INTG16 in Internal Interrupt Combiner.
- */
-
-static uint32_t
-combiner_grp_to_gic_id[64-EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][8] = {
- /* int combiner groups 16-19 */
- { }, { }, { }, { },
- /* int combiner group 20 */
- { 0, EXT_GIC_ID_MDMA_LCD0 },
- /* int combiner group 21 */
- { EXT_GIC_ID_PDMA0, EXT_GIC_ID_PDMA1 },
- /* int combiner group 22 */
- { EXT_GIC_ID_TIMER0, EXT_GIC_ID_TIMER1, EXT_GIC_ID_TIMER2,
- EXT_GIC_ID_TIMER3, EXT_GIC_ID_TIMER4 },
- /* int combiner group 23 */
- { EXT_GIC_ID_RTC_ALARM, EXT_GIC_ID_RTC_TIC },
- /* int combiner group 24 */
- { EXT_GIC_ID_GPIO_XB, EXT_GIC_ID_GPIO_XA },
- /* int combiner group 25 */
- { EXT_GIC_ID_IEM_APC, EXT_GIC_ID_IEM_IEC },
- /* int combiner group 26 */
- { EXT_GIC_ID_UART0, EXT_GIC_ID_UART1, EXT_GIC_ID_UART2, EXT_GIC_ID_UART3,
- EXT_GIC_ID_UART4 },
- /* int combiner group 27 */
- { EXT_GIC_ID_I2C0, EXT_GIC_ID_I2C1, EXT_GIC_ID_I2C2, EXT_GIC_ID_I2C3,
- EXT_GIC_ID_I2C4, EXT_GIC_ID_I2C5, EXT_GIC_ID_I2C6,
- EXT_GIC_ID_I2C7 },
- /* int combiner group 28 */
- { EXT_GIC_ID_SPI0, EXT_GIC_ID_SPI1, EXT_GIC_ID_SPI2 },
- /* int combiner group 29 */
- { EXT_GIC_ID_HSMMC0, EXT_GIC_ID_HSMMC1, EXT_GIC_ID_HSMMC2,
- EXT_GIC_ID_HSMMC3, EXT_GIC_ID_SDMMC },
- /* int combiner group 30 */
- { EXT_GIC_ID_MIPI_CSI_4LANE, EXT_GIC_ID_MIPI_CSI_2LANE },
- /* int combiner group 31 */
- { EXT_GIC_ID_MIPI_DSI_4LANE, EXT_GIC_ID_MIPI_DSI_2LANE },
- /* int combiner group 32 */
- { EXT_GIC_ID_FIMC0, EXT_GIC_ID_FIMC1 },
- /* int combiner group 33 */
- { EXT_GIC_ID_FIMC2, EXT_GIC_ID_FIMC3 },
- /* int combiner group 34 */
- { EXT_GIC_ID_ONENAND_AUDI, EXT_GIC_ID_NFC },
- /* int combiner group 35 */
- { 0, 0, 0, EXT_GIC_ID_MCT_L1, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
- /* int combiner group 36 */
- { EXT_GIC_ID_MIXER },
- /* int combiner group 37 */
- { EXT_GIC_ID_EXTINT4, EXT_GIC_ID_EXTINT5, EXT_GIC_ID_EXTINT6,
- EXT_GIC_ID_EXTINT7 },
- /* int combiner group 38 */
- { EXT_GIC_ID_EXTINT8, EXT_GIC_ID_EXTINT9, EXT_GIC_ID_EXTINT10,
- EXT_GIC_ID_EXTINT11, EXT_GIC_ID_EXTINT12, EXT_GIC_ID_EXTINT13,
- EXT_GIC_ID_EXTINT14, EXT_GIC_ID_EXTINT15 },
- /* int combiner groups 39-43 */
- { EXT_GIC_ID_EXTINT16_31 },
- { EXT_GIC_ID_EXTINT0 },
- { EXT_GIC_ID_EXTINT1 },
- { EXT_GIC_ID_EXTINT2 },
- { EXT_GIC_ID_EXTINT3 },
- /* groups 44-50 */
- { }, { }, { }, { }, { }, { }, { },
- /* int combiner group 51 */
- { EXT_GIC_ID_MCT_L0, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
- /* group 52 */
- { },
- /* int combiner group 53 */
- { EXT_GIC_ID_WDT, 0, 0, 0, EXT_GIC_ID_MCT_G0, EXT_GIC_ID_MCT_G1 },
- /* groups 54-63 */
- { }, { }, { }, { }, { }, { }, { }, { }, { }, { }
-};
-
-#define EXYNOS4210_GIC_NIRQ 160
-
-#define EXYNOS4210_EXT_GIC_CPU_REGION_SIZE 0x10000
-#define EXYNOS4210_EXT_GIC_DIST_REGION_SIZE 0x10000
-
-#define EXYNOS4210_EXT_GIC_PER_CPU_OFFSET 0x8000
-#define EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(n) \
- ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
-#define EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(n) \
- ((n) * EXYNOS4210_EXT_GIC_PER_CPU_OFFSET)
-
-#define EXYNOS4210_GIC_CPU_REGION_SIZE 0x100
-#define EXYNOS4210_GIC_DIST_REGION_SIZE 0x1000
-
-static void exynos4210_irq_handler(void *opaque, int irq, int level)
-{
- Exynos4210Irq *s = (Exynos4210Irq *)opaque;
-
- /* Bypass */
- qemu_set_irq(s->board_irqs[irq], level);
-
- return;
-}
-
-/*
- * Initialize exynos4210 IRQ subsystem stub.
- */
-qemu_irq *exynos4210_init_irq(Exynos4210Irq *s)
-{
- return qemu_allocate_irqs(exynos4210_irq_handler, s,
- EXYNOS4210_MAX_INT_COMBINER_IN_IRQ);
-}
-
-/*
- * Initialize board IRQs.
- * These IRQs contain splitted Int/External Combiner and External Gic IRQs.
- */
-void exynos4210_init_board_irqs(Exynos4210Irq *s)
-{
- uint32_t grp, bit, irq_id, n;
-
- for (n = 0; n < EXYNOS4210_MAX_EXT_COMBINER_IN_IRQ; n++) {
- s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
- s->ext_combiner_irq[n]);
-
- irq_id = 0;
- if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 4) ||
- n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 4)) {
- /* MCT_G0 is passed to External GIC */
- irq_id = EXT_GIC_ID_MCT_G0;
- }
- if (n == EXYNOS4210_COMBINER_GET_IRQ_NUM(1, 5) ||
- n == EXYNOS4210_COMBINER_GET_IRQ_NUM(12, 5)) {
- /* MCT_G1 is passed to External and GIC */
- irq_id = EXT_GIC_ID_MCT_G1;
- }
- if (irq_id) {
- s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
- s->ext_gic_irq[irq_id-32]);
- }
-
- }
- for (; n < EXYNOS4210_MAX_INT_COMBINER_IN_IRQ; n++) {
- /* these IDs are passed to Internal Combiner and External GIC */
- grp = EXYNOS4210_COMBINER_GET_GRP_NUM(n);
- bit = EXYNOS4210_COMBINER_GET_BIT_NUM(n);
- irq_id = combiner_grp_to_gic_id[grp -
- EXYNOS4210_MAX_EXT_COMBINER_OUT_IRQ][bit];
-
- if (irq_id) {
- s->board_irqs[n] = qemu_irq_split(s->int_combiner_irq[n],
- s->ext_gic_irq[irq_id-32]);
- }
- }
-}
-
-/*
- * Get IRQ number from exynos4210 IRQ subsystem stub.
- * To identify IRQ source use internal combiner group and bit number
- * grp - group number
- * bit - bit number inside group
- */
-uint32_t exynos4210_get_irq(uint32_t grp, uint32_t bit)
-{
- return EXYNOS4210_COMBINER_GET_IRQ_NUM(grp, bit);
-}
-
-/********* GIC part *********/
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion cpu_container;
- MemoryRegion dist_container;
- MemoryRegion cpu_alias[EXYNOS4210_NCPUS];
- MemoryRegion dist_alias[EXYNOS4210_NCPUS];
- uint32_t num_cpu;
- DeviceState *gic;
-} Exynos4210GicState;
-
-static void exynos4210_gic_set_irq(void *opaque, int irq, int level)
-{
- Exynos4210GicState *s = (Exynos4210GicState *)opaque;
- qemu_set_irq(qdev_get_gpio_in(s->gic, irq), level);
-}
-
-static int exynos4210_gic_init(SysBusDevice *dev)
-{
- Exynos4210GicState *s = FROM_SYSBUS(Exynos4210GicState, dev);
- uint32_t i;
- const char cpu_prefix[] = "exynos4210-gic-alias_cpu";
- const char dist_prefix[] = "exynos4210-gic-alias_dist";
- char cpu_alias_name[sizeof(cpu_prefix) + 3];
- char dist_alias_name[sizeof(cpu_prefix) + 3];
- SysBusDevice *busdev;
-
- s->gic = qdev_create(NULL, "arm_gic");
- qdev_prop_set_uint32(s->gic, "num-cpu", s->num_cpu);
- qdev_prop_set_uint32(s->gic, "num-irq", EXYNOS4210_GIC_NIRQ);
- qdev_init_nofail(s->gic);
- busdev = sysbus_from_qdev(s->gic);
-
- /* Pass through outbound IRQ lines from the GIC */
- sysbus_pass_irq(dev, busdev);
-
- /* Pass through inbound GPIO lines to the GIC */
- qdev_init_gpio_in(&s->busdev.qdev, exynos4210_gic_set_irq,
- EXYNOS4210_GIC_NIRQ - 32);
-
- memory_region_init(&s->cpu_container, "exynos4210-cpu-container",
- EXYNOS4210_EXT_GIC_CPU_REGION_SIZE);
- memory_region_init(&s->dist_container, "exynos4210-dist-container",
- EXYNOS4210_EXT_GIC_DIST_REGION_SIZE);
-
- for (i = 0; i < s->num_cpu; i++) {
- /* Map CPU interface per SMP Core */
- sprintf(cpu_alias_name, "%s%x", cpu_prefix, i);
- memory_region_init_alias(&s->cpu_alias[i],
- cpu_alias_name,
- sysbus_mmio_get_region(busdev, 1),
- 0,
- EXYNOS4210_GIC_CPU_REGION_SIZE);
- memory_region_add_subregion(&s->cpu_container,
- EXYNOS4210_EXT_GIC_CPU_GET_OFFSET(i), &s->cpu_alias[i]);
-
- /* Map Distributor per SMP Core */
- sprintf(dist_alias_name, "%s%x", dist_prefix, i);
- memory_region_init_alias(&s->dist_alias[i],
- dist_alias_name,
- sysbus_mmio_get_region(busdev, 0),
- 0,
- EXYNOS4210_GIC_DIST_REGION_SIZE);
- memory_region_add_subregion(&s->dist_container,
- EXYNOS4210_EXT_GIC_DIST_GET_OFFSET(i), &s->dist_alias[i]);
- }
-
- sysbus_init_mmio(dev, &s->cpu_container);
- sysbus_init_mmio(dev, &s->dist_container);
-
- return 0;
-}
-
-static Property exynos4210_gic_properties[] = {
- DEFINE_PROP_UINT32("num-cpu", Exynos4210GicState, num_cpu, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_gic_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_gic_init;
- dc->props = exynos4210_gic_properties;
-}
-
-static TypeInfo exynos4210_gic_info = {
- .name = "exynos4210.gic",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210GicState),
- .class_init = exynos4210_gic_class_init,
-};
-
-static void exynos4210_gic_register_types(void)
-{
- type_register_static(&exynos4210_gic_info);
-}
-
-type_init(exynos4210_gic_register_types)
-
-/* IRQ OR Gate struct.
- *
- * This device models an OR gate. There are n_in input qdev gpio lines and one
- * output sysbus IRQ line. The output IRQ level is formed as OR between all
- * gpio inputs.
- */
-typedef struct {
- SysBusDevice busdev;
-
- uint32_t n_in; /* inputs amount */
- uint32_t *level; /* input levels */
- qemu_irq out; /* output IRQ */
-} Exynos4210IRQGateState;
-
-static Property exynos4210_irq_gate_properties[] = {
- DEFINE_PROP_UINT32("n_in", Exynos4210IRQGateState, n_in, 1),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static const VMStateDescription vmstate_exynos4210_irq_gate = {
- .name = "exynos4210.irq_gate",
- .version_id = 2,
- .minimum_version_id = 2,
- .minimum_version_id_old = 2,
- .fields = (VMStateField[]) {
- VMSTATE_VBUFFER_UINT32(level, Exynos4210IRQGateState, 1, NULL, 0, n_in),
- VMSTATE_END_OF_LIST()
- }
-};
-
-/* Process a change in IRQ input. */
-static void exynos4210_irq_gate_handler(void *opaque, int irq, int level)
-{
- Exynos4210IRQGateState *s = (Exynos4210IRQGateState *)opaque;
- uint32_t i;
-
- assert(irq < s->n_in);
-
- s->level[irq] = level;
-
- for (i = 0; i < s->n_in; i++) {
- if (s->level[i] >= 1) {
- qemu_irq_raise(s->out);
- return;
- }
- }
-
- qemu_irq_lower(s->out);
-
- return;
-}
-
-static void exynos4210_irq_gate_reset(DeviceState *d)
-{
- Exynos4210IRQGateState *s =
- DO_UPCAST(Exynos4210IRQGateState, busdev.qdev, d);
-
- memset(s->level, 0, s->n_in * sizeof(*s->level));
-}
-
-/*
- * IRQ Gate initialization.
- */
-static int exynos4210_irq_gate_init(SysBusDevice *dev)
-{
- Exynos4210IRQGateState *s = FROM_SYSBUS(Exynos4210IRQGateState, dev);
-
- /* Allocate general purpose input signals and connect a handler to each of
- * them */
- qdev_init_gpio_in(&s->busdev.qdev, exynos4210_irq_gate_handler, s->n_in);
-
- s->level = g_malloc0(s->n_in * sizeof(*s->level));
-
- sysbus_init_irq(dev, &s->out);
-
- return 0;
-}
-
-static void exynos4210_irq_gate_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_irq_gate_init;
- dc->reset = exynos4210_irq_gate_reset;
- dc->vmsd = &vmstate_exynos4210_irq_gate;
- dc->props = exynos4210_irq_gate_properties;
-}
-
-static TypeInfo exynos4210_irq_gate_info = {
- .name = "exynos4210.irq_gate",
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210IRQGateState),
- .class_init = exynos4210_irq_gate_class_init,
-};
-
-static void exynos4210_irq_gate_register_types(void)
-{
- type_register_static(&exynos4210_irq_gate_info);
-}
-
-type_init(exynos4210_irq_gate_register_types)
+++ /dev/null
-/*
- * Samsung exynos4210 I2S driver
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Vorobiov Stanislav <s.vorobiov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "exynos4210_i2s.h"
-#include "exec-memory.h"
-
-/* #define DEBUG_I2S */
-
-#ifdef DEBUG_I2S
-#define DPRINTF(fmt, ...) \
- do { \
- fprintf(stdout, "I2S: [%s:%d] " fmt, __func__, __LINE__, \
- ## __VA_ARGS__); \
- } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-/* Registers */
-#define IISCON 0x00
-#define IISMOD 0x04
-#define IISFIC 0x08
-#define IISPSR 0x0C
-#define IISTXD 0x10
-#define IISRXD 0x14
-#define IISFICS 0x18
-#define IISTXDS 0x1C
-#define IISAHB 0x20
-#define IISSTR0 0x24
-#define IISSIZE 0x28
-#define IISTRNCNT 0x2C
-#define IISLVL0ADDR 0x30
-#define IISLVL1ADDR 0x34
-#define IISLVL2ADDR 0x38
-#define IISLVL3ADDR 0x3C
-#define IISSTR1 0x40
-
-#define I2S_REGS_MEM_SIZE 0x44
-#define I2S_REGS_NUM (I2S_REGS_MEM_SIZE >> 2)
-
-#define I_(reg) (reg / sizeof(uint32_t))
-
-/* Interface Control Register */
-#define IISCON_I2SACTIVE (1 << 0)
-#define IISCON_RXDMACTIVE (1 << 1)
-#define IISCON_TXDMACTIVE (1 << 2)
-#define IISCON_RXCHPAUSE (1 << 3)
-#define IISCON_TXCHPAUSE (1 << 4)
-#define IISCON_RXDMAPAUSE (1 << 5)
-#define IISCON_TXDMAPAUSE (1 << 6)
-#define IISCON_FRXFULL (1 << 7)
-#define IISCON_FTX0FULL (1 << 8)
-#define IISCON_FRXEMPT (1 << 9)
-#define IISCON_FTX0EMPT (1 << 10)
-#define IISCON_LRI (1 << 11)
-#define IISCON_FTX1FULL (1 << 12)
-#define IISCON_FTX2FULL (1 << 13)
-#define IISCON_FTX1EMPT (1 << 14)
-#define IISCON_FTX2EMPT (1 << 15)
-#define IISCON_FTXURINTEN (1 << 16)
-#define IISCON_FTXURSTATUS (1 << 17)
-#define IISCON_TXSDMACTIVE (1 << 18)
-#define IISCON_TXSDMAPAUSE (1 << 20)
-#define IISCON_FTXSFULL (1 << 21)
-#define IISCON_FTXSEMPT (1 << 22)
-#define IISCON_FTXSURINTEN (1 << 23)
-#define IISCON_FTXSURSTATUS (1 << 24)
-#define IISCON_FRXOFINTEN (1 << 25)
-#define IISCON_FRXOFSTATUS (1 << 26)
-#define IISCON_SW_RST (1 << 31)
-
-#define IISCON_WRITE_MASK (0x8295007F)
-
-/* AHB DMA Control Register */
-#define IISAHB_WRITE_MASK 0xFF0000FB
-#define IISAHB_LVL3EN (1 << 27)
-#define IISAHB_LVL2EN (1 << 26)
-#define IISAHB_LVL1EN (1 << 25)
-#define IISAHB_LVL0EN (1 << 24)
-#define IISAHB_LVL3INT (1 << 23)
-#define IISAHB_LVL2INT (1 << 22)
-#define IISAHB_LVL1INT (1 << 21)
-#define IISAHB_LVL0INT (1 << 20)
-#define IISAHB_LVL3CLR (1 << 19)
-#define IISAHB_LVL2CLR (1 << 18)
-#define IISAHB_LVL1CLR (1 << 17)
-#define IISAHB_LVL0CLR (1 << 16)
-#define IISAHB_DMA_STRADDRRST (1 << 7)
-#define IISAHB_DMA_STRADDRTOG (1 << 6)
-#define IISAHB_DMARLD (1 << 5)
-#define IISAHB_INTMASK (1 << 3)
-#define IISAHB_DMAINT (1 << 2)
-#define IISAHB_DMACLR (1 << 1)
-#define IISAHB_DMAEN (1 << 0)
-
-/* AHB DMA Size Register */
-#define IISSIZE_TRNS_SIZE_OFFSET 16
-#define IISSIZE_TRNS_SIZE_MASK 0xFFFF
-
-/* AHB DMA Transfer Count Register */
-#define IISTRNCNT_OFFSET 0
-#define IISTRNCNT_MASK 0xFFFFFF
-
-typedef struct {
- const char *name;
- target_phys_addr_t offset;
- uint32_t reset_value;
-} Exynos4210I2SReg;
-
-static Exynos4210I2SReg exynos4210_i2s_regs[I2S_REGS_NUM] = {
- {"IISCON", IISCON, 0x00000000},
- {"IISMOD", IISMOD, 0x00000000},
- {"IISFIC", IISFIC, 0x00000000},
- {"IISPSR", IISPSR, 0x00000000},
- {"IISTXD", IISTXD, 0x00000000},
- {"IISRXD", IISRXD, 0x00000000},
- {"IISFICS", IISFICS, 0x00000000},
- {"IISTXDS", IISTXDS, 0x00000000},
- {"IISAHB", IISAHB, 0x00000000},
- {"IISSTR0", IISSTR0, 0x00000000},
- {"IISSIZE", IISSIZE, 0x7FFF0000},
- {"IISTRNCNT", IISTRNCNT, 0x00000000},
- {"IISLVL0ADDR", IISLVL0ADDR, 0x00000000},
- {"IISLVL1ADDR", IISLVL1ADDR, 0x00000000},
- {"IISLVL2ADDR", IISLVL2ADDR, 0x00000000},
- {"IISLVL3ADDR", IISLVL3ADDR, 0x00000000},
- {"IISSTR1", IISSTR1, 0x00000000},
-};
-
-static struct {
- uint32_t ahb_en_bit;
- uint32_t ahb_int_bit;
- uint32_t ahb_clr_bit;
- int reg_offset;
-} lvl_regs[] = {
- { IISAHB_LVL3EN, IISAHB_LVL3INT, IISAHB_LVL3CLR, IISLVL3ADDR },
- { IISAHB_LVL2EN, IISAHB_LVL2INT, IISAHB_LVL2CLR, IISLVL2ADDR },
- { IISAHB_LVL1EN, IISAHB_LVL1INT, IISAHB_LVL1CLR, IISLVL1ADDR },
- { IISAHB_LVL0EN, IISAHB_LVL0INT, IISAHB_LVL0CLR, IISLVL0ADDR },
-};
-
-#define TYPE_EXYNOS4210_I2S_BUS "exynos4210-i2s"
-
-typedef struct {
- BusState qbus;
-
- MemoryRegion iomem;
- qemu_irq irq;
- uint32_t reg[I2S_REGS_NUM];
-} Exynos4210I2SBus;
-
-static Exynos4210I2SSlave *get_slave(Exynos4210I2SBus *bus)
-{
- BusChild *kid = QTAILQ_FIRST(&bus->qbus.children);
- DeviceState *dev;
-
- if (kid) {
- dev = kid->child;
- if (dev) {
- return EXYNOS4210_I2S_SLAVE_FROM_QDEV(dev);
- }
- }
-
- return NULL;
-}
-
-static void reset_internal(BusState *qbus, bool reset_slave)
-{
- Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus);
- Exynos4210I2SSlave *s;
- int i;
-
- DPRINTF("enter\n");
-
- qemu_irq_lower(bus->irq);
-
- for (i = 0; i < ARRAY_SIZE(exynos4210_i2s_regs); i++) {
- bus->reg[i] = exynos4210_i2s_regs[i].reset_value;
- }
-
- if (reset_slave) {
- s = get_slave(bus);
-
- if (s != NULL) {
- device_reset(&s->qdev);
- }
- }
-}
-
-static uint32_t get_dma_size_words(Exynos4210I2SBus *bus)
-{
- return (bus->reg[I_(IISSIZE)] >> IISSIZE_TRNS_SIZE_OFFSET) &
- IISSIZE_TRNS_SIZE_MASK;
-}
-
-static uint32_t get_dma_trncnt_words(Exynos4210I2SBus *bus)
-{
- return (bus->reg[I_(IISTRNCNT)] >> IISTRNCNT_OFFSET) &
- IISTRNCNT_MASK;
-}
-
-static void set_dma_trncnt_words(Exynos4210I2SBus *bus, uint32_t trncnt_words)
-{
- bus->reg[I_(IISTRNCNT)] &= ~(IISTRNCNT_MASK << IISTRNCNT_OFFSET);
- bus->reg[I_(IISTRNCNT)] |=
- ((trncnt_words & IISTRNCNT_MASK) << IISTRNCNT_OFFSET);
-}
-
-static int exynos4210_i2s_bus_reset(BusState *qbus);
-
-static void exynos4210_i2s_bus_class_init(ObjectClass *klass, void *data)
-{
- BusClass *k = BUS_CLASS(klass);
-
- k->reset = exynos4210_i2s_bus_reset;
-}
-
-static struct TypeInfo exynos4210_i2s_bus_info = {
- .name = TYPE_EXYNOS4210_I2S_BUS,
- .parent = TYPE_BUS,
- .instance_size = sizeof(Exynos4210I2SBus),
- .class_init = exynos4210_i2s_bus_class_init,
-};
-
-static const VMStateDescription vmstate_exynos4210_i2s_bus = {
- .name = "exynos4210.i2s_bus",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32_ARRAY(reg, Exynos4210I2SBus,
- I2S_REGS_NUM),
- VMSTATE_END_OF_LIST()
- }
-};
-
-#ifdef DEBUG_I2S
-static const char *exynos4210_i2s_regname(Exynos4210I2SBus *bus,
- target_phys_addr_t offset)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(exynos4210_i2s_regs); i++) {
- if (offset == exynos4210_i2s_regs[i].offset) {
- return exynos4210_i2s_regs[i].name;
- }
- }
-
- return NULL;
-}
-#endif
-
-static void exynos4210_i2s_bus_write(void *opaque,
- target_phys_addr_t offset,
- uint64_t value,
- unsigned size)
-{
- Exynos4210I2SBus *bus = opaque;
- Exynos4210I2SSlave *s;
- Exynos4210I2SSlaveClass *sc;
- int i;
-
- s = get_slave(bus);
-
- assert(s != NULL);
-
- if (s == NULL) {
- hw_error("Exynos I2S cannot operate without a slave\n");
- }
-
- sc = EXYNOS4210_I2S_SLAVE_GET_CLASS(s);
-
- switch (offset) {
- case IISCON:
- if (!(value & IISCON_SW_RST) &&
- (bus->reg[I_(IISCON)] & IISCON_SW_RST)) {
- reset_internal(&bus->qbus, 1);
- }
-
- bus->reg[I_(offset)] = (bus->reg[I_(offset)] & ~IISCON_WRITE_MASK) |
- (value & IISCON_WRITE_MASK);
-
- DPRINTF("0x%.8X -> %s\n",
- bus->reg[I_(offset)],
- exynos4210_i2s_regname(bus, offset));
-
- break;
- case IISAHB:
- if (((value & IISAHB_DMAEN) != 0) && ((value & IISAHB_DMARLD) == 0)) {
- hw_error("Non auto-reload DMA is not supported\n");
- }
-
- if (((value & IISAHB_DMAEN) != 0) && ((value & IISAHB_INTMASK) == 0)) {
- hw_error("Non buffer level DMA interrupt is not supported\n");
- }
-
- if (((value & IISAHB_DMAEN) != 0) &&
- ((value & IISAHB_DMA_STRADDRTOG) != 0)) {
- hw_error("DMA start address toggle is not supported\n");
- }
-
- for (i = 0; i < ARRAY_SIZE(lvl_regs); ++i) {
- if ((value & lvl_regs[i].ahb_clr_bit) &&
- (bus->reg[I_(IISAHB)] & lvl_regs[i].ahb_int_bit)) {
- qemu_irq_lower(bus->irq);
- bus->reg[I_(IISAHB)] &= ~lvl_regs[i].ahb_int_bit;
- }
- }
-
- if ((value & IISAHB_DMACLR) &&
- (bus->reg[I_(IISAHB)] & IISAHB_DMAINT)) {
- qemu_irq_lower(bus->irq);
- bus->reg[I_(IISAHB)] &= ~IISAHB_DMAINT;
- }
-
- if ((value & IISAHB_DMAEN) !=
- (bus->reg[I_(IISAHB)] & IISAHB_DMAEN)) {
- if ((value & IISAHB_DMAEN) == 0) {
- qemu_irq_lower(bus->irq);
- }
- if (sc->dma_enable) {
- sc->dma_enable(s, ((value & IISAHB_DMAEN) != 0));
- }
- }
-
- bus->reg[I_(offset)] = (bus->reg[I_(offset)] & ~IISAHB_WRITE_MASK) |
- (value & IISAHB_WRITE_MASK);
-
- DPRINTF("0x%.8X -> %s\n",
- bus->reg[I_(offset)],
- exynos4210_i2s_regname(bus, offset));
-
- break;
- case IISTRNCNT:
- hw_error("Cannot write IISTRNCNT\n");
- break;
- case IISSIZE:
- if (value == 0) {
- hw_error("IISSIZE cannot be 0\n");
- }
-
- bus->reg[I_(offset)] = value;
-
- if (get_dma_size_words(bus) <= get_dma_trncnt_words(bus)) {
- set_dma_trncnt_words(bus, 0);
- }
-
- DPRINTF("0x%.8X -> %s\n",
- bus->reg[I_(offset)],
- exynos4210_i2s_regname(bus, offset));
-
- break;
- case IISLVL0ADDR:
- case IISLVL1ADDR:
- case IISLVL2ADDR:
- case IISLVL3ADDR:
- case IISTXD:
- case IISMOD:
- case IISFIC:
- case IISPSR:
- case IISTXDS:
- case IISFICS:
- case IISSTR0:
- case IISSTR1:
- bus->reg[I_(offset)] = value;
-
- DPRINTF("0x%.8X -> %s\n",
- bus->reg[I_(offset)],
- exynos4210_i2s_regname(bus, offset));
-
- break;
- default:
- hw_error("Bad offset: 0x%X\n", (int)offset);
- }
-}
-
-static uint64_t exynos4210_i2s_bus_read(void *opaque,
- target_phys_addr_t offset,
- unsigned size)
-{
- Exynos4210I2SBus *bus = opaque;
-
- if (offset > (I2S_REGS_MEM_SIZE - sizeof(uint32_t))) {
- hw_error("Bad offset: 0x%X\n", (int)offset);
- return 0;
- }
-
- DPRINTF("%s -> 0x%.8X\n",
- exynos4210_i2s_regname(bus, offset),
- bus->reg[I_(offset)]);
-
- return bus->reg[I_(offset)];
-}
-
-static int exynos4210_i2s_bus_reset(BusState *qbus)
-{
- reset_internal(qbus, 0);
-
- return 0;
-}
-
-static const MemoryRegionOps exynos4210_i2s_bus_ops = {
- .read = exynos4210_i2s_bus_read,
- .write = exynos4210_i2s_bus_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .max_access_size = 4,
- .unaligned = false
- },
-};
-
-BusState *exynos4210_i2s_bus_new(const char *name,
- target_phys_addr_t addr,
- qemu_irq irq)
-{
- Exynos4210I2SBus *bus;
-
- bus = FROM_QBUS(Exynos4210I2SBus,
- qbus_create(TYPE_EXYNOS4210_I2S_BUS, NULL, name));
- vmstate_register(NULL, -1, &vmstate_exynos4210_i2s_bus, bus);
-
- memory_region_init_io(&bus->iomem,
- &exynos4210_i2s_bus_ops,
- bus,
- "exynos4210.i2s",
- I2S_REGS_MEM_SIZE);
-
- memory_region_add_subregion(get_system_memory(),
- addr,
- &bus->iomem);
-
- bus->irq = irq;
-
- return &bus->qbus;
-}
-
-bool exynos4210_i2s_dma_enabled(BusState *qbus)
-{
- Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus);
-
- return ((bus->reg[I_(IISAHB)] & IISAHB_DMAEN) != 0);
-}
-
-uint32_t exynos4210_i2s_dma_get_words_available(BusState *qbus)
-{
- Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus);
-
- return get_dma_size_words(bus);
-}
-
-void exynos4210_i2s_dma_read(BusState *qbus, void *buf, uint32_t num_words)
-{
- Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus);
- target_phys_addr_t addr;
- uint32_t size_words, trncnt_words;
-
- assert(num_words <= exynos4210_i2s_dma_get_words_available(qbus));
-
- if (num_words > exynos4210_i2s_dma_get_words_available(qbus)) {
- hw_error("Bad DMA read length: %d\n", num_words);
- }
-
- size_words = get_dma_size_words(bus);
- addr = bus->reg[I_(IISSTR0)];
- trncnt_words = get_dma_trncnt_words(bus);
-
- assert(trncnt_words < size_words);
-
- if (num_words > (size_words - trncnt_words)) {
- cpu_physical_memory_read(addr +
- (trncnt_words * EXYNOS4210_I2S_WORD_LEN),
- buf,
- (size_words - trncnt_words) * EXYNOS4210_I2S_WORD_LEN);
- num_words -= (size_words - trncnt_words);
- buf += (size_words - trncnt_words) * EXYNOS4210_I2S_WORD_LEN;
- trncnt_words = 0;
- }
-
- cpu_physical_memory_read(addr + (trncnt_words * EXYNOS4210_I2S_WORD_LEN),
- buf,
- num_words * EXYNOS4210_I2S_WORD_LEN);
-}
-
-void exynos4210_i2s_dma_advance(BusState *qbus, uint32_t num_words)
-{
- Exynos4210I2SBus *bus = DO_UPCAST(Exynos4210I2SBus, qbus, qbus);
- uint32_t size_words, trncnt_words;
- int i;
-
- assert(num_words <= exynos4210_i2s_dma_get_words_available(qbus));
-
- if (num_words > exynos4210_i2s_dma_get_words_available(qbus)) {
- hw_error("Bad DMA read length: %d\n", num_words);
- }
-
- size_words = get_dma_size_words(bus);
- trncnt_words = get_dma_trncnt_words(bus);
-
- for (i = 0; i < ARRAY_SIZE(lvl_regs); ++i) {
- target_phys_addr_t dma_offset;
- uint32_t tmp_num_words = num_words, tmp_trncnt_words = trncnt_words;
-
- if ((bus->reg[I_(IISAHB)] & lvl_regs[i].ahb_en_bit) == 0) {
- continue;
- }
-
- if (bus->reg[I_(lvl_regs[i].reg_offset)] < bus->reg[I_(IISSTR0)]) {
- continue;
- }
-
- dma_offset = bus->reg[I_(lvl_regs[i].reg_offset)] -
- bus->reg[I_(IISSTR0)];
-
- if (tmp_num_words > (size_words - tmp_trncnt_words)) {
- if ((dma_offset >= (tmp_trncnt_words * EXYNOS4210_I2S_WORD_LEN)) &&
- (dma_offset < size_words * EXYNOS4210_I2S_WORD_LEN)) {
- bus->reg[I_(IISAHB)] |= lvl_regs[i].ahb_int_bit;
- qemu_irq_raise(bus->irq);
- break;
- }
-
- tmp_num_words -= (size_words - tmp_trncnt_words);
- tmp_trncnt_words = 0;
- }
-
- if ((dma_offset >= (tmp_trncnt_words * EXYNOS4210_I2S_WORD_LEN)) &&
- (dma_offset <
- (tmp_trncnt_words + tmp_num_words) * EXYNOS4210_I2S_WORD_LEN)) {
- bus->reg[I_(IISAHB)] |= lvl_regs[i].ahb_int_bit;
- qemu_irq_raise(bus->irq);
- }
- }
-
- set_dma_trncnt_words(bus, (trncnt_words + num_words) % size_words);
-}
-
-const VMStateDescription vmstate_exynos4210_i2s_slave = {
- .name = "Exynos4210I2SSlave",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1
-};
-
-static int exynos4210_i2s_slave_qdev_init(DeviceState *dev)
-{
- Exynos4210I2SSlave *s = EXYNOS4210_I2S_SLAVE_FROM_QDEV(dev);
- Exynos4210I2SSlaveClass *sc = EXYNOS4210_I2S_SLAVE_GET_CLASS(s);
-
- return sc->init ? sc->init(s) : 0;
-}
-
-static void exynos4210_i2s_slave_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *k = DEVICE_CLASS(klass);
- k->init = exynos4210_i2s_slave_qdev_init;
- k->bus_type = TYPE_EXYNOS4210_I2S_BUS;
-}
-
-static TypeInfo exynos4210_i2s_slave_type_info = {
- .name = TYPE_EXYNOS4210_I2S_SLAVE,
- .parent = TYPE_DEVICE,
- .instance_size = sizeof(Exynos4210I2SSlave),
- .abstract = true,
- .class_size = sizeof(Exynos4210I2SSlaveClass),
- .class_init = exynos4210_i2s_slave_class_init,
-};
-
-static void exynos4210_i2s_slave_register_types(void)
-{
- type_register_static(&exynos4210_i2s_bus_info);
- type_register_static(&exynos4210_i2s_slave_type_info);
-}
-
-type_init(exynos4210_i2s_slave_register_types)
+++ /dev/null
-#ifndef QEMU_HW_EXYNOS4210_I2S_H
-#define QEMU_HW_EXYNOS4210_I2S_H
-
-#include "qdev.h"
-
-#define EXYNOS4210_I2S_WORD_LEN 4
-
-typedef struct Exynos4210I2SSlave Exynos4210I2SSlave;
-
-#define TYPE_EXYNOS4210_I2S_SLAVE "exynos4210.i2s-slave"
-#define EXYNOS4210_I2S_SLAVE(obj) \
- OBJECT_CHECK(Exynos4210I2SSlave, (obj), TYPE_EXYNOS4210_I2S_SLAVE)
-#define EXYNOS4210_I2S_SLAVE_CLASS(klass) \
- OBJECT_CLASS_CHECK(Exynos4210I2SSlaveClass, (klass), \
- TYPE_EXYNOS4210_I2S_SLAVE)
-#define EXYNOS4210_I2S_SLAVE_GET_CLASS(obj) \
- OBJECT_GET_CLASS(Exynos4210I2SSlaveClass, (obj), TYPE_EXYNOS4210_I2S_SLAVE)
-
-typedef struct {
- DeviceClass parent_class;
-
- int (*init)(Exynos4210I2SSlave *s);
-
- void (*dma_enable)(Exynos4210I2SSlave *s, bool enable);
-} Exynos4210I2SSlaveClass;
-
-struct Exynos4210I2SSlave {
- DeviceState qdev;
-};
-
-BusState *exynos4210_i2s_bus_new(const char *name,
- target_phys_addr_t addr,
- qemu_irq irq);
-
-#define EXYNOS4210_I2S_SLAVE_FROM_QDEV(dev) \
- DO_UPCAST(Exynos4210I2SSlave, qdev, dev)
-#define FROM_EXYNOS4210_I2S_SLAVE(type, dev) DO_UPCAST(type, i2s, dev)
-
-bool exynos4210_i2s_dma_enabled(BusState *qbus);
-
-uint32_t exynos4210_i2s_dma_get_words_available(BusState *qbus);
-
-void exynos4210_i2s_dma_read(BusState *qbus, void *buf, uint32_t num_words);
-
-void exynos4210_i2s_dma_advance(BusState *qbus, uint32_t num_words);
-
-extern const VMStateDescription vmstate_exynos4210_i2s_slave;
-
-#define VMSTATE_EXYNOS4210_I2S_SLAVE(_field, _state) { \
- .name = (stringify(_field)), \
- .size = sizeof(Exynos4210I2SSlave), \
- .vmsd = &vmstate_exynos4210_i2s_slave, \
- .flags = VMS_STRUCT, \
- .offset = vmstate_offset_value(_state, _field, Exynos4210I2SSlave), \
-}
-
-#endif
+++ /dev/null
-/*
- * Exynos4210 UART Emulation
- *
- * Copyright (C) 2011 Samsung Electronics Co Ltd.
- * Maksim Kozlov, <m.kozlov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "sysbus.h"
-#include "sysemu.h"
-#include "qemu-char.h"
-
-#include "exynos4210.h"
-
-#define DEBUG_UART 0
-#define DEBUG_UART_EXTEND 0
-#define DEBUG_IRQ 0
-#define DEBUG_Rx_DATA 0
-#define DEBUG_Tx_DATA 0
-
-#if DEBUG_UART || DEBUG_UART_EXTEND
-#define PRINT_DEBUG(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-#if DEBUG_UART_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_EXTEND(fmt, args...) \
- do {} while (0)
-#endif
-
-#define PRINT_ERROR(fmt, args...) \
- do { \
- fprintf(stderr, " [%s:%d] "fmt, __func__, __LINE__, ##args); \
- } while (0)
-
-/*
- * Offsets for UART registers relative to SFR base address
- * for UARTn
- *
- */
-#define ULCON 0x0000 /* Line Control */
-#define UCON 0x0004 /* Control */
-#define UFCON 0x0008 /* FIFO Control */
-#define UMCON 0x000C /* Modem Control */
-#define UTRSTAT 0x0010 /* Tx/Rx Status */
-#define UERSTAT 0x0014 /* UART Error Status */
-#define UFSTAT 0x0018 /* FIFO Status */
-#define UMSTAT 0x001C /* Modem Status */
-#define UTXH 0x0020 /* Transmit Buffer */
-#define URXH 0x0024 /* Receive Buffer */
-#define UBRDIV 0x0028 /* Baud Rate Divisor */
-#define UFRACVAL 0x002C /* Divisor Fractional Value */
-#define UINTP 0x0030 /* Interrupt Pending */
-#define UINTSP 0x0034 /* Interrupt Source Pending */
-#define UINTM 0x0038 /* Interrupt Mask */
-
-/*
- * for indexing register in the uint32_t array
- *
- * 'reg' - register offset (see offsets definitions above)
- *
- */
-#define I_(reg) (reg / sizeof(uint32_t))
-
-typedef struct Exynos4210UartReg {
- const char *name; /* the only reason is the debug output */
- target_phys_addr_t offset;
- uint32_t reset_value;
-} Exynos4210UartReg;
-
-static Exynos4210UartReg exynos4210_uart_regs[] = {
- {"ULCON", ULCON, 0x00000000},
- {"UCON", UCON, 0x00003000},
- {"UFCON", UFCON, 0x00000000},
- {"UMCON", UMCON, 0x00000000},
- {"UTRSTAT", UTRSTAT, 0x00000006}, /* RO */
- {"UERSTAT", UERSTAT, 0x00000000}, /* RO */
- {"UFSTAT", UFSTAT, 0x00000000}, /* RO */
- {"UMSTAT", UMSTAT, 0x00000000}, /* RO */
- {"UTXH", UTXH, 0x5c5c5c5c}, /* WO, undefined reset value*/
- {"URXH", URXH, 0x00000000}, /* RO */
- {"UBRDIV", UBRDIV, 0x00000000},
- {"UFRACVAL", UFRACVAL, 0x00000000},
- {"UINTP", UINTP, 0x00000000},
- {"UINTSP", UINTSP, 0x00000000},
- {"UINTM", UINTM, 0x00000000},
-};
-
-#define EXYNOS4210_UART_REGS_MEM_SIZE 0x3C
-
-/* UART FIFO Control */
-#define UFCON_FIFO_ENABLE 0x1
-#define UFCON_Rx_FIFO_RESET 0x2
-#define UFCON_Tx_FIFO_RESET 0x4
-#define UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT 8
-#define UFCON_Tx_FIFO_TRIGGER_LEVEL (7 << UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT)
-#define UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT 4
-#define UFCON_Rx_FIFO_TRIGGER_LEVEL (7 << UFCON_Rx_FIFO_TRIGGER_LEVEL_SHIFT)
-
-/* Uart FIFO Status */
-#define UFSTAT_Rx_FIFO_COUNT 0xff
-#define UFSTAT_Rx_FIFO_FULL 0x100
-#define UFSTAT_Rx_FIFO_ERROR 0x200
-#define UFSTAT_Tx_FIFO_COUNT_SHIFT 16
-#define UFSTAT_Tx_FIFO_COUNT (0xff << UFSTAT_Tx_FIFO_COUNT_SHIFT)
-#define UFSTAT_Tx_FIFO_FULL_SHIFT 24
-#define UFSTAT_Tx_FIFO_FULL (1 << UFSTAT_Tx_FIFO_FULL_SHIFT)
-
-/* UART Interrupt Source Pending */
-#define UINTSP_RXD 0x1 /* Receive interrupt */
-#define UINTSP_ERROR 0x2 /* Error interrupt */
-#define UINTSP_TXD 0x4 /* Transmit interrupt */
-#define UINTSP_MODEM 0x8 /* Modem interrupt */
-
-/* UART Line Control */
-#define ULCON_IR_MODE_SHIFT 6
-#define ULCON_PARITY_SHIFT 3
-#define ULCON_STOP_BIT_SHIFT 1
-
-/* UART Tx/Rx Status */
-#define UTRSTAT_TRANSMITTER_EMPTY 0x4
-#define UTRSTAT_Tx_BUFFER_EMPTY 0x2
-#define UTRSTAT_Rx_BUFFER_DATA_READY 0x1
-
-/* UART Error Status */
-#define UERSTAT_OVERRUN 0x1
-#define UERSTAT_PARITY 0x2
-#define UERSTAT_FRAME 0x4
-#define UERSTAT_BREAK 0x8
-
-#define TYPE_EXYNOS4210_UART "exynos4210.uart"
-
-typedef struct {
- uint8_t *data;
- uint32_t sp, rp; /* store and retrieve pointers */
- uint32_t size;
-} Exynos4210UartFIFO;
-
-typedef struct {
- SysBusDevice busdev;
- MemoryRegion iomem;
-
- uint32_t reg[EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)];
- Exynos4210UartFIFO rx;
- Exynos4210UartFIFO tx;
-
- CharDriverState *chr;
- qemu_irq irq;
-
- uint32_t channel;
-
-} Exynos4210UartState;
-
-
-#if DEBUG_UART || DEBUG_UART_EXTEND
-/* Used only for debugging inside PRINT_DEBUG_... macros */
-static const char *exynos4210_uart_regname(target_phys_addr_t offset)
-{
-
- int regs_number = sizeof(exynos4210_uart_regs) / sizeof(Exynos4210UartReg);
- int i;
-
- for (i = 0; i < regs_number; i++) {
- if (offset == exynos4210_uart_regs[i].offset) {
- return exynos4210_uart_regs[i].name;
- }
- }
-
- return NULL;
-}
-#endif
-
-
-static void fifo_store(Exynos4210UartFIFO *q, uint8_t ch)
-{
- q->data[q->sp] = ch;
- q->sp = (q->sp + 1) % q->size;
-}
-
-static uint8_t fifo_retrieve(Exynos4210UartFIFO *q)
-{
- uint8_t ret = q->data[q->rp];
- q->rp = (q->rp + 1) % q->size;
- return ret;
-}
-
-static int fifo_elements_number(Exynos4210UartFIFO *q)
-{
- if (q->sp < q->rp) {
- return q->size - q->rp + q->sp;
- }
-
- return q->sp - q->rp;
-}
-
-static int fifo_empty_elements_number(Exynos4210UartFIFO *q)
-{
- return q->size - fifo_elements_number(q);
-}
-
-static void fifo_reset(Exynos4210UartFIFO *q)
-{
- if (q->data != NULL) {
- g_free(q->data);
- q->data = NULL;
- }
-
- q->data = (uint8_t *)g_malloc0(q->size);
-
- q->sp = 0;
- q->rp = 0;
-}
-
-static uint32_t exynos4210_uart_Tx_FIFO_trigger_level(Exynos4210UartState *s)
-{
- uint32_t level = 0;
- uint32_t reg;
-
- reg = (s->reg[I_(UFCON)] & UFCON_Tx_FIFO_TRIGGER_LEVEL) >>
- UFCON_Tx_FIFO_TRIGGER_LEVEL_SHIFT;
-
- switch (s->channel) {
- case 0:
- level = reg * 32;
- break;
- case 1:
- case 4:
- level = reg * 8;
- break;
- case 2:
- case 3:
- level = reg * 2;
- break;
- default:
- level = 0;
- PRINT_ERROR("Wrong UART channel number: %d\n", s->channel);
- }
-
- return level;
-}
-
-static void exynos4210_uart_update_irq(Exynos4210UartState *s)
-{
- /*
- * The Tx interrupt is always requested if the number of data in the
- * transmit FIFO is smaller than the trigger level.
- */
- if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
-
- uint32_t count = (s->reg[I_(UFSTAT)] & UFSTAT_Tx_FIFO_COUNT) >>
- UFSTAT_Tx_FIFO_COUNT_SHIFT;
-
- if (count <= exynos4210_uart_Tx_FIFO_trigger_level(s)) {
- s->reg[I_(UINTSP)] |= UINTSP_TXD;
- }
- }
-
- s->reg[I_(UINTP)] = s->reg[I_(UINTSP)] & ~s->reg[I_(UINTM)];
-
- if (s->reg[I_(UINTP)]) {
- qemu_irq_raise(s->irq);
-
-#if DEBUG_IRQ
- fprintf(stderr, "UART%d: IRQ has been raised: %08x\n",
- s->channel, s->reg[I_(UINTP)]);
-#endif
-
- } else {
- qemu_irq_lower(s->irq);
- }
-}
-
-static void exynos4210_uart_update_parameters(Exynos4210UartState *s)
-{
- int speed, parity, data_bits, stop_bits, frame_size;
- QEMUSerialSetParams ssp;
- uint64_t uclk_rate;
-
- if (s->reg[I_(UBRDIV)] == 0) {
- PRINT_DEBUG("Baud rate division value is 0\n");
- return;
- }
-
- frame_size = 1; /* start bit */
- if (s->reg[I_(ULCON)] & 0x20) {
- frame_size++; /* parity bit */
- if (s->reg[I_(ULCON)] & 0x28) {
- parity = 'E';
- } else {
- parity = 'O';
- }
- } else {
- parity = 'N';
- }
-
- if (s->reg[I_(ULCON)] & 0x4) {
- stop_bits = 2;
- } else {
- stop_bits = 1;
- }
-
- data_bits = (s->reg[I_(ULCON)] & 0x3) + 5;
-
- frame_size += data_bits + stop_bits;
-
- switch (s->channel) {
- case 0:
- uclk_rate = exynos4210_cmu_get_rate(EXYNOS4210_SCLK_UART0); break;
- case 1:
- uclk_rate = exynos4210_cmu_get_rate(EXYNOS4210_SCLK_UART1); break;
- case 2:
- uclk_rate = exynos4210_cmu_get_rate(EXYNOS4210_SCLK_UART2); break;
- case 3:
- uclk_rate = exynos4210_cmu_get_rate(EXYNOS4210_SCLK_UART3); break;
- default:
- hw_error("%s: Incorrect UART channel: %d\n",
- __func__, s->channel);
- }
-
- speed = uclk_rate / ((16 * (s->reg[I_(UBRDIV)]) & 0xffff) +
- (s->reg[I_(UFRACVAL)] & 0x7) + 16);
-
- ssp.speed = speed;
- ssp.parity = parity;
- ssp.data_bits = data_bits;
- ssp.stop_bits = stop_bits;
-
- qemu_chr_fe_ioctl(s->chr, CHR_IOCTL_SERIAL_SET_PARAMS, &ssp);
-
- PRINT_DEBUG("UART%d: speed: %d, parity: %c, data: %d, stop: %d\n",
- s->channel, speed, parity, data_bits, stop_bits);
-}
-
-static void uclk_rate_changed(void *opaque)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
-
- PRINT_DEBUG("Clock sclk_uart%d was changed\n", s->channel);
-
- exynos4210_uart_update_parameters(s);
-}
-
-static void exynos4210_uart_write(void *opaque, target_phys_addr_t offset,
- uint64_t val, unsigned size)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
- uint8_t ch;
-
- PRINT_DEBUG_EXTEND("UART%d: <0x%04x> %s <- 0x%08llx\n", s->channel,
- offset, exynos4210_uart_regname(offset), (long long unsigned int)val);
-
- switch (offset) {
- case ULCON:
- case UBRDIV:
- case UFRACVAL:
- s->reg[I_(offset)] = val;
- exynos4210_uart_update_parameters(s);
- break;
- case UFCON:
- s->reg[I_(UFCON)] = val;
- if (val & UFCON_Rx_FIFO_RESET) {
- fifo_reset(&s->rx);
- s->reg[I_(UFCON)] &= ~UFCON_Rx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Rx FIFO Reset\n", s->channel);
- }
- if (val & UFCON_Tx_FIFO_RESET) {
- fifo_reset(&s->tx);
- s->reg[I_(UFCON)] &= ~UFCON_Tx_FIFO_RESET;
- PRINT_DEBUG("UART%d: Tx FIFO Reset\n", s->channel);
- }
- break;
-
- case UTXH:
- if (s->chr) {
- s->reg[I_(UTRSTAT)] &= ~(UTRSTAT_TRANSMITTER_EMPTY |
- UTRSTAT_Tx_BUFFER_EMPTY);
- ch = (uint8_t)val;
- qemu_chr_fe_write(s->chr, &ch, 1);
-#if DEBUG_Tx_DATA
- fprintf(stderr, "%c", ch);
-#endif
- s->reg[I_(UTRSTAT)] |= UTRSTAT_TRANSMITTER_EMPTY |
- UTRSTAT_Tx_BUFFER_EMPTY;
- s->reg[I_(UINTSP)] |= UINTSP_TXD;
- exynos4210_uart_update_irq(s);
- }
- break;
-
- case UINTP:
- s->reg[I_(UINTP)] &= ~val;
- s->reg[I_(UINTSP)] &= ~val;
- PRINT_DEBUG("UART%d: UINTP [%04x] have been cleared: %08x\n",
- s->channel, offset, s->reg[I_(UINTP)]);
- exynos4210_uart_update_irq(s);
- break;
- case UTRSTAT:
- case UERSTAT:
- case UFSTAT:
- case UMSTAT:
- case URXH:
- PRINT_DEBUG("UART%d: Trying to write into RO register: %s [%04x]\n",
- s->channel, exynos4210_uart_regname(offset), offset);
- break;
- case UINTSP:
- s->reg[I_(UINTSP)] &= ~val;
- break;
- case UINTM:
- s->reg[I_(UINTM)] = val;
- exynos4210_uart_update_irq(s);
- break;
- case UCON:
- case UMCON:
- default:
- s->reg[I_(offset)] = val;
- break;
- }
-}
-static uint64_t exynos4210_uart_read(void *opaque, target_phys_addr_t offset,
- unsigned size)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
- uint32_t res;
-
- switch (offset) {
- case UERSTAT: /* Read Only */
- res = s->reg[I_(UERSTAT)];
- s->reg[I_(UERSTAT)] = 0;
- return res;
- case UFSTAT: /* Read Only */
- s->reg[I_(UFSTAT)] = fifo_elements_number(&s->rx) & 0xff;
- if (fifo_empty_elements_number(&s->rx) == 0) {
- s->reg[I_(UFSTAT)] |= UFSTAT_Rx_FIFO_FULL;
- s->reg[I_(UFSTAT)] &= ~0xff;
- }
- return s->reg[I_(UFSTAT)];
- case URXH:
- if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
- if (fifo_elements_number(&s->rx)) {
- res = fifo_retrieve(&s->rx);
-#if DEBUG_Rx_DATA
- fprintf(stderr, "%c", res);
-#endif
- if (!fifo_elements_number(&s->rx)) {
- s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
- } else {
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- }
- } else {
- s->reg[I_(UINTSP)] |= UINTSP_ERROR;
- exynos4210_uart_update_irq(s);
- res = 0;
- }
- } else {
- s->reg[I_(UTRSTAT)] &= ~UTRSTAT_Rx_BUFFER_DATA_READY;
- res = s->reg[I_(URXH)];
- }
- return res;
- case UTXH:
- PRINT_DEBUG("UART%d: Trying to read from WO register: %s [%04x]\n",
- s->channel, exynos4210_uart_regname(offset), offset);
- break;
- default:
- return s->reg[I_(offset)];
- }
-
- return 0;
-}
-
-static const MemoryRegionOps exynos4210_uart_ops = {
- .read = exynos4210_uart_read,
- .write = exynos4210_uart_write,
- .endianness = DEVICE_NATIVE_ENDIAN,
- .valid = {
- .max_access_size = 4,
- .unaligned = false
- },
-};
-
-static int exynos4210_uart_can_receive(void *opaque)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
-
- return fifo_empty_elements_number(&s->rx);
-}
-
-
-static void exynos4210_uart_receive(void *opaque, const uint8_t *buf, int size)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
- int i;
-
- if (s->reg[I_(UFCON)] & UFCON_FIFO_ENABLE) {
- if (fifo_empty_elements_number(&s->rx) < size) {
- for (i = 0; i < fifo_empty_elements_number(&s->rx); i++) {
- fifo_store(&s->rx, buf[i]);
- }
- s->reg[I_(UINTSP)] |= UINTSP_ERROR;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- } else {
- for (i = 0; i < size; i++) {
- fifo_store(&s->rx, buf[i]);
- }
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- }
- /* XXX: Around here we maybe should check Rx trigger level */
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
- } else {
- s->reg[I_(URXH)] = buf[0];
- s->reg[I_(UINTSP)] |= UINTSP_RXD;
- s->reg[I_(UTRSTAT)] |= UTRSTAT_Rx_BUFFER_DATA_READY;
- }
-
- exynos4210_uart_update_irq(s);
-}
-
-
-static void exynos4210_uart_event(void *opaque, int event)
-{
- Exynos4210UartState *s = (Exynos4210UartState *)opaque;
-
- if (event == CHR_EVENT_BREAK) {
- /* When the RxDn is held in logic 0, then a null byte is pushed into the
- * fifo */
- fifo_store(&s->rx, '\0');
- s->reg[I_(UERSTAT)] |= UERSTAT_BREAK;
- exynos4210_uart_update_irq(s);
- }
-}
-
-
-static void exynos4210_uart_reset(DeviceState *dev)
-{
- Exynos4210UartState *s =
- container_of(dev, Exynos4210UartState, busdev.qdev);
- int regs_number = sizeof(exynos4210_uart_regs)/sizeof(Exynos4210UartReg);
- int i;
- Exynos4210Clock clock_id;
-
- for (i = 0; i < regs_number; i++) {
- s->reg[I_(exynos4210_uart_regs[i].offset)] =
- exynos4210_uart_regs[i].reset_value;
- }
-
- fifo_reset(&s->rx);
- fifo_reset(&s->tx);
-
- switch (s->channel) {
- case 0: clock_id = EXYNOS4210_SCLK_UART0; break;
- case 1: clock_id = EXYNOS4210_SCLK_UART1; break;
- case 2: clock_id = EXYNOS4210_SCLK_UART2; break;
- case 3: clock_id = EXYNOS4210_SCLK_UART3; break;
- default:
- hw_error("Wrong channel number: %d.\n", s->channel);
- }
-
- exynos4210_register_clock_handler(uclk_rate_changed, clock_id, s);
-
- PRINT_DEBUG("UART%d: Rx FIFO size: %d\n", s->channel, s->rx.size);
-}
-
-static const VMStateDescription vmstate_exynos4210_uart_fifo = {
- .name = "exynos4210.uart.fifo",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_UINT32(sp, Exynos4210UartFIFO),
- VMSTATE_UINT32(rp, Exynos4210UartFIFO),
- VMSTATE_VBUFFER_UINT32(data, Exynos4210UartFIFO, 1, NULL, 0, size),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static const VMStateDescription vmstate_exynos4210_uart = {
- .name = "exynos4210.uart",
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .fields = (VMStateField[]) {
- VMSTATE_STRUCT(rx, Exynos4210UartState, 1,
- vmstate_exynos4210_uart_fifo, Exynos4210UartFIFO),
- VMSTATE_UINT32_ARRAY(reg, Exynos4210UartState,
- EXYNOS4210_UART_REGS_MEM_SIZE / sizeof(uint32_t)),
- VMSTATE_END_OF_LIST()
- }
-};
-
-DeviceState *exynos4210_uart_create(target_phys_addr_t addr,
- int fifo_size,
- int channel,
- CharDriverState *chr,
- qemu_irq irq)
-{
- DeviceState *dev;
- SysBusDevice *bus;
-
- const char chr_name[] = "serial";
- char label[ARRAY_SIZE(chr_name) + 1];
-
- dev = qdev_create(NULL, "exynos4210.uart");
-
- if (!chr) {
- if (channel >= MAX_SERIAL_PORTS) {
- hw_error("Only %d serial ports are supported by QEMU.\n",
- MAX_SERIAL_PORTS);
- }
- chr = serial_hds[channel];
- if (!chr) {
- snprintf(label, ARRAY_SIZE(label), "%s%d", chr_name, channel);
- chr = qemu_chr_new(label, "null", NULL);
- if (!(chr)) {
- hw_error("Can't assign serial port to UART%d.\n", channel);
- }
- }
- }
-
- qdev_prop_set_chr(dev, "chardev", chr);
- qdev_prop_set_uint32(dev, "channel", channel);
- qdev_prop_set_uint32(dev, "rx-size", fifo_size);
- qdev_prop_set_uint32(dev, "tx-size", fifo_size);
-
- bus = sysbus_from_qdev(dev);
- qdev_init_nofail(dev);
- if (addr != (target_phys_addr_t)-1) {
- sysbus_mmio_map(bus, 0, addr);
- }
- sysbus_connect_irq(bus, 0, irq);
-
- return dev;
-}
-
-static int exynos4210_uart_init(SysBusDevice *dev)
-{
- Exynos4210UartState *s = FROM_SYSBUS(Exynos4210UartState, dev);
-
- /* memory mapping */
- memory_region_init_io(&s->iomem, &exynos4210_uart_ops, s, "exynos4210.uart",
- EXYNOS4210_UART_REGS_MEM_SIZE);
- sysbus_init_mmio(dev, &s->iomem);
-
- sysbus_init_irq(dev, &s->irq);
-
- qemu_chr_add_handlers(s->chr, exynos4210_uart_can_receive,
- exynos4210_uart_receive, exynos4210_uart_event, s);
-
- return 0;
-}
-
-
-static Property exynos4210_uart_properties[] = {
- DEFINE_PROP_CHR("chardev", Exynos4210UartState, chr),
- DEFINE_PROP_UINT32("channel", Exynos4210UartState, channel, 0),
- DEFINE_PROP_UINT32("rx-size", Exynos4210UartState, rx.size, 16),
- DEFINE_PROP_UINT32("tx-size", Exynos4210UartState, tx.size, 16),
- DEFINE_PROP_END_OF_LIST(),
-};
-
-static void exynos4210_uart_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- SysBusDeviceClass *k = SYS_BUS_DEVICE_CLASS(klass);
-
- k->init = exynos4210_uart_init;
- dc->reset = exynos4210_uart_reset;
- dc->props = exynos4210_uart_properties;
- dc->vmsd = &vmstate_exynos4210_uart;
-}
-
-static TypeInfo exynos4210_uart_info = {
- .name = TYPE_EXYNOS4210_UART,
- .parent = TYPE_SYS_BUS_DEVICE,
- .instance_size = sizeof(Exynos4210UartState),
- .class_init = exynos4210_uart_class_init,
-};
-
-static void exynos4210_uart_register(void)
-{
- type_register_static(&exynos4210_uart_info);
-}
-
-type_init(exynos4210_uart_register)
+++ /dev/null
-/*
- * Samsung exynos4210 wm8994 driver
- *
- * Copyright (c) 2012 Samsung Electronics Co., Ltd.
- * Vorobiov Stanislav <s.vorobiov@samsung.com>
- *
- * This program is free software; you can redistribute it and/or modify it
- * under the terms of the GNU General Public License as published by the
- * Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful, but WITHOUT
- * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
- * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
- * for more details.
- *
- * You should have received a copy of the GNU General Public License along
- * with this program; if not, see <http://www.gnu.org/licenses/>.
- *
- */
-
-#include "wm8994.h"
-#include "hw.h"
-#include "i2c.h"
-#include "audio/audio.h"
-
-/* #define DEBUG_WM8994 */
-
-#ifdef DEBUG_WM8994
-#define DPRINTF(fmt, ...) \
- do { \
- fprintf(stdout, "WM8994: [%s:%d] " fmt, __func__, __LINE__, \
- ## __VA_ARGS__); \
- } while (0)
-#else
-#define DPRINTF(fmt, ...) do {} while (0)
-#endif
-
-/* Registers */
-#define WM8994_SOFTWARE_RESET 0x00
-#define WM8994_POWER_MANAGEMENT_2 0x02
-#define WM8994_SPEAKER_VOLUME_LEFT 0x26 /* Speaker */
-#define WM8994_SPEAKER_VOLUME_RIGHT 0x27
-#define WM8994_CHIP_REVISION 0x100
-#define WM8994_AIF1_RATE 0x210
-#define WM8994_AIF1_CONTROL_1 0x300
-#define WM8994_GPIO_1 0x700
-#define WM8994_GPIO_3 0x702
-#define WM8994_GPIO_4 0x703
-#define WM8994_GPIO_5 0x704
-#define WM8994_GPIO_6 0x705
-#define WM8994_GPIO_7 0x706
-#define WM8994_GPIO_8 0x707
-#define WM8994_GPIO_9 0x708
-#define WM8994_GPIO_10 0x709
-#define WM8994_GPIO_11 0x70A
-#define WM8994_PULL_CONTROL_2 0x721
-#define WM8994_INPUT_MIXER_1 0x15
-#define WM8994_LEFT_LINE_INPUT_1_2_VOLUME 0x18
-#define WM8994_LEFT_LINE_INPUT_3_4_VOLUME 0x19
-#define WM8994_RIGHT_LINE_INPUT_1_2_VOLUME 0x1A
-#define WM8994_RIGHT_LINE_INPUT_3_4_VOLUME 0x1B
-#define WM8994_LEFT_OUTPUT_VOLUME 0x1C
-#define WM8994_RIGHT_OUTPUT_VOLUME 0x1D
-#define WM8994_LEFT_OPGA_VOLUME 0x20
-#define WM8994_RIGHT_OPGA_VOLUME 0x21
-#define WM8994_LINE_MIXER_1 0x34
-#define WM8994_LINE_MIXER_2 0x35
-#define WM8994_ANTIPOP_1 0x38
-#define WM8994_LDO_1 0x3B
-#define WM8994_LDO_2 0x3C
-#define WM8994_AIF1_ADC1_LEFT_VOLUME 0x400
-#define WM8994_AIF1_ADC1_RIGHT_VOLUME 0x401
-#define WM8994_AIF1_DAC1_LEFT_VOLUME 0x402
-#define WM8994_AIF1_DAC1_RIGHT_VOLUME 0x403
-#define WM8994_AIF1_ADC2_LEFT_VOLUME 0x404
-#define WM8994_AIF1_ADC2_RIGHT_VOLUME 0x405
-#define WM8994_AIF1_DAC2_LEFT_VOLUME 0x406
-#define WM8994_AIF1_DAC2_RIGHT_VOLUME 0x407
-#define WM8994_AIF1_DAC1_FILTERS_2 0x421
-#define WM8994_AIF1_DAC2_FILTERS_2 0x423
-#define WM8994_AIF2_ADC_LEFT_VOLUME 0x500
-#define WM8994_AIF2_ADC_RIGHT_VOLUME 0x501
-#define WM8994_AIF2_DAC_LEFT_VOLUME 0x502
-#define WM8994_AIF2_DAC_RIGHT_VOLUME 0x503
-#define WM8994_AIF2_DAC_FILTERS_2 0x521
-#define WM8994_DAC1_LEFT_VOLUME 0x610
-#define WM8994_DAC1_RIGHT_VOLUME 0x611
-#define WM8994_DAC2_LEFT_VOLUME 0x612
-#define WM8994_DAC2_RIGHT_VOLUME 0x613
-#define WM8994_POWER_MANAGEMENT_1 0x01
-#define WM8994_POWER_MANAGEMENT_3 0x03
-#define WM8994_ANTIPOP_2 0x39
-#define WM8994_AIF1_CLOCKING_1 0x200
-#define WM8994_FLL1_CONTROL_1 0x220
-#define WM8994_FLL1_CONTROL_2 0x221
-#define WM8994_FLL1_CONTROL_3 0x222
-#define WM8994_FLL1_CONTROL_4 0x223
-#define WM8994_FLL1_CONTROL_5 0x224
-#define WM8994_AIF1_MASTER_SLAVE 0x302
-#define WM8994_AIF1_BCLK 0x303
-#define WM8994_AIF1DAC_LRCLK 0x305
-#define WM8994_AIF1_DAC1_FILTERS_1 0x420
-
-#define WM8994_REGS_NUM 0x74A
-
-/*
- * R528 (0x210) - AIF1 Rate
- */
-#define WM8994_AIF1_SR_MASK 0x00F0 /* AIF1_SR - [7:4] */
-#define WM8994_AIF1_SR_SHIFT 4 /* AIF1_SR - [7:4] */
-#define WM8994_AIF1_SR_WIDTH 4 /* AIF1_SR - [7:4] */
-#define WM8994_AIF1CLK_RATE_MASK 0x000F /* AIF1CLK_RATE - [3:0] */
-#define WM8994_AIF1CLK_RATE_SHIFT 0 /* AIF1CLK_RATE - [3:0] */
-#define WM8994_AIF1CLK_RATE_WIDTH 4 /* AIF1CLK_RATE - [3:0] */
-
-/*
- * R768 (0x300) - AIF1 Control (1)
- */
-#define WM8994_AIF1ADCL_SRC 0x8000 /* AIF1ADCL_SRC */
-#define WM8994_AIF1ADCL_SRC_MASK 0x8000 /* AIF1ADCL_SRC */
-#define WM8994_AIF1ADCL_SRC_SHIFT 15 /* AIF1ADCL_SRC */
-#define WM8994_AIF1ADCL_SRC_WIDTH 1 /* AIF1ADCL_SRC */
-#define WM8994_AIF1ADCR_SRC 0x4000 /* AIF1ADCR_SRC */
-#define WM8994_AIF1ADCR_SRC_MASK 0x4000 /* AIF1ADCR_SRC */
-#define WM8994_AIF1ADCR_SRC_SHIFT 14 /* AIF1ADCR_SRC */
-#define WM8994_AIF1ADCR_SRC_WIDTH 1 /* AIF1ADCR_SRC */
-#define WM8994_AIF1ADC_TDM 0x2000 /* AIF1ADC_TDM */
-#define WM8994_AIF1ADC_TDM_MASK 0x2000 /* AIF1ADC_TDM */
-#define WM8994_AIF1ADC_TDM_SHIFT 13 /* AIF1ADC_TDM */
-#define WM8994_AIF1ADC_TDM_WIDTH 1 /* AIF1ADC_TDM */
-#define WM8994_AIF1_BCLK_INV 0x0100 /* AIF1_BCLK_INV */
-#define WM8994_AIF1_BCLK_INV_MASK 0x0100 /* AIF1_BCLK_INV */
-#define WM8994_AIF1_BCLK_INV_SHIFT 8 /* AIF1_BCLK_INV */
-#define WM8994_AIF1_BCLK_INV_WIDTH 1 /* AIF1_BCLK_INV */
-#define WM8994_AIF1_LRCLK_INV 0x0080 /* AIF1_LRCLK_INV */
-#define WM8994_AIF1_LRCLK_INV_MASK 0x0080 /* AIF1_LRCLK_INV */
-#define WM8994_AIF1_LRCLK_INV_SHIFT 7 /* AIF1_LRCLK_INV */
-#define WM8994_AIF1_LRCLK_INV_WIDTH 1 /* AIF1_LRCLK_INV */
-#define WM8994_AIF1_WL_MASK 0x0060 /* AIF1_WL - [6:5] */
-#define WM8994_AIF1_WL_SHIFT 5 /* AIF1_WL - [6:5] */
-#define WM8994_AIF1_WL_WIDTH 2 /* AIF1_WL - [6:5] */
-#define WM8994_AIF1_FMT_MASK 0x0018 /* AIF1_FMT - [4:3] */
-#define WM8994_AIF1_FMT_SHIFT 3 /* AIF1_FMT - [4:3] */
-#define WM8994_AIF1_FMT_WIDTH 2 /* AIF1_FMT - [4:3] */
-
-/*
- * R1056 (0x420) - AIF1 DAC1 Filters (1)
- */
-#define WM8994_AIF1DAC1_MUTE 0x0200 /* AIF1DAC1_MUTE */
-#define WM8994_AIF1DAC1_MUTE_MASK 0x0200 /* AIF1DAC1_MUTE */
-#define WM8994_AIF1DAC1_MUTE_SHIFT 9 /* AIF1DAC1_MUTE */
-#define WM8994_AIF1DAC1_MUTE_WIDTH 1 /* AIF1DAC1_MUTE */
-#define WM8994_AIF1DAC1_MONO 0x0080 /* AIF1DAC1_MONO */
-#define WM8994_AIF1DAC1_MONO_MASK 0x0080 /* AIF1DAC1_MONO */
-#define WM8994_AIF1DAC1_MONO_SHIFT 7 /* AIF1DAC1_MONO */
-#define WM8994_AIF1DAC1_MONO_WIDTH 1 /* AIF1DAC1_MONO */
-#define WM8994_AIF1DAC1_MUTERATE 0x0020 /* AIF1DAC1_MUTERATE */
-#define WM8994_AIF1DAC1_MUTERATE_MASK 0x0020 /* AIF1DAC1_MUTERATE */
-#define WM8994_AIF1DAC1_MUTERATE_SHIFT 5 /* AIF1DAC1_MUTERATE */
-#define WM8994_AIF1DAC1_MUTERATE_WIDTH 1 /* AIF1DAC1_MUTERATE */
-#define WM8994_AIF1DAC1_UNMUTE_RAMP 0x0010 /* AIF1DAC1_UNMUTE_RAMP */
-#define WM8994_AIF1DAC1_UNMUTE_RAMP_MASK 0x0010 /* AIF1DAC1_UNMUTE_RAMP */
-#define WM8994_AIF1DAC1_UNMUTE_RAMP_SHIFT 4 /* AIF1DAC1_UNMUTE_RAMP */
-#define WM8994_AIF1DAC1_UNMUTE_RAMP_WIDTH 1 /* AIF1DAC1_UNMUTE_RAMP */
-#define WM8994_AIF1DAC1_DEEMP_MASK 0x0006 /* AIF1DAC1_DEEMP - [2:1] */
-#define WM8994_AIF1DAC1_DEEMP_SHIFT 1 /* AIF1DAC1_DEEMP - [2:1] */
-#define WM8994_AIF1DAC1_DEEMP_WIDTH 2 /* AIF1DAC1_DEEMP - [2:1] */
-
-/*
- * R38 (0x26), R39 (0x27) - Speaker Volume
- */
-#define WM8994_SPKOUT_VU 0x0100 /* SPKOUT_VU */
-#define WM8994_SPKOUT_VU_MASK 0x0100 /* SPKOUT_VU */
-#define WM8994_SPKOUT_VU_SHIFT 8 /* SPKOUT_VU */
-#define WM8994_SPKOUT_VU_WIDTH 1 /* SPKOUT_VU */
-#define WM8994_SPKOUTL_ZC 0x0080 /* SPKOUTL_ZC */
-#define WM8994_SPKOUTL_ZC_MASK 0x0080 /* SPKOUTL_ZC */
-#define WM8994_SPKOUTL_ZC_SHIFT 7 /* SPKOUTL_ZC */
-#define WM8994_SPKOUTL_ZC_WIDTH 1 /* SPKOUTL_ZC */
-#define WM8994_SPKOUTL_MUTE_N 0x0040 /* SPKOUTL_MUTE_N */
-#define WM8994_SPKOUTL_MUTE_N_MASK 0x0040 /* SPKOUTL_MUTE_N */
-#define WM8994_SPKOUTL_MUTE_N_SHIFT 6 /* SPKOUTL_MUTE_N */
-#define WM8994_SPKOUTL_MUTE_N_WIDTH 1 /* SPKOUTL_MUTE_N */
-#define WM8994_SPKOUTL_VOL_MASK 0x003F /* SPKOUTL_VOL - [5:0] */
-#define WM8994_SPKOUTL_VOL_SHIFT 0 /* SPKOUTL_VOL - [5:0] */
-#define WM8994_SPKOUTL_VOL_WIDTH 6 /* SPKOUTL_VOL - [5:0] */
-
-#define CODEC "wm8994"
-
-typedef struct {
- const char *name;
- uint16_t address;
-} WM8994Reg;
-
-#ifdef DEBUG_WM8994
-static WM8994Reg wm8994_regs[] = {
- {"SOFTWARE_RESET", WM8994_SOFTWARE_RESET },
- {"POWER_MANAGEMENT_2", WM8994_POWER_MANAGEMENT_2 },
- {"SPEAKER_VOLUME_LEFT", WM8994_SPEAKER_VOLUME_LEFT },
- {"SPEAKER_VOLUME_RIGHT", WM8994_SPEAKER_VOLUME_RIGHT },
- {"CHIP_REVISION", WM8994_CHIP_REVISION },
- {"AIF1_RATE", WM8994_AIF1_RATE },
- {"AIF1_CONTROL_1", WM8994_AIF1_CONTROL_1 },
- {"GPIO_1", WM8994_GPIO_1 },
- {"GPIO_3", WM8994_GPIO_3 },
- {"GPIO_4", WM8994_GPIO_4 },
- {"GPIO_5", WM8994_GPIO_5 },
- {"GPIO_6", WM8994_GPIO_6 },
- {"GPIO_7", WM8994_GPIO_7 },
- {"GPIO_8", WM8994_GPIO_8 },
- {"GPIO_9", WM8994_GPIO_9 },
- {"GPIO_10", WM8994_GPIO_10 },
- {"GPIO_11", WM8994_GPIO_11 },
- {"PULL_CONTROL_2", WM8994_PULL_CONTROL_2 },
- {"INPUT_MIXER_1", WM8994_INPUT_MIXER_1 },
- {"LEFT_LINE_INPUT_1_2_VOLUME", WM8994_LEFT_LINE_INPUT_1_2_VOLUME },
- {"LEFT_LINE_INPUT_3_4_VOLUME", WM8994_LEFT_LINE_INPUT_3_4_VOLUME },
- {"RIGHT_LINE_INPUT_1_2_VOLUME", WM8994_RIGHT_LINE_INPUT_1_2_VOLUME },
- {"RIGHT_LINE_INPUT_3_4_VOLUME", WM8994_RIGHT_LINE_INPUT_3_4_VOLUME },
- {"LEFT_OUTPUT_VOLUME", WM8994_LEFT_OUTPUT_VOLUME },
- {"RIGHT_OUTPUT_VOLUME", WM8994_RIGHT_OUTPUT_VOLUME },
- {"LEFT_OPGA_VOLUME", WM8994_LEFT_OPGA_VOLUME },
- {"RIGHT_OPGA_VOLUME", WM8994_RIGHT_OPGA_VOLUME },
- {"LINE_MIXER_1", WM8994_LINE_MIXER_1 },
- {"LINE_MIXER_2", WM8994_LINE_MIXER_2 },
- {"ANTIPOP_1", WM8994_ANTIPOP_1 },
- {"LDO_1", WM8994_LDO_1 },
- {"LDO_2", WM8994_LDO_2 },
- {"AIF1_ADC1_LEFT_VOLUME", WM8994_AIF1_ADC1_LEFT_VOLUME },
- {"AIF1_ADC1_RIGHT_VOLUME", WM8994_AIF1_ADC1_RIGHT_VOLUME },
- {"AIF1_DAC1_LEFT_VOLUME", WM8994_AIF1_DAC1_LEFT_VOLUME },
- {"AIF1_DAC1_RIGHT_VOLUME", WM8994_AIF1_DAC1_RIGHT_VOLUME },
- {"AIF1_ADC2_LEFT_VOLUME", WM8994_AIF1_ADC2_LEFT_VOLUME },
- {"AIF1_ADC2_RIGHT_VOLUME", WM8994_AIF1_ADC2_RIGHT_VOLUME },
- {"AIF1_DAC2_LEFT_VOLUME", WM8994_AIF1_DAC2_LEFT_VOLUME },
- {"AIF1_DAC2_RIGHT_VOLUME", WM8994_AIF1_DAC2_RIGHT_VOLUME },
- {"AIF1_DAC1_FILTERS_2", WM8994_AIF1_DAC1_FILTERS_2 },
- {"AIF1_DAC2_FILTERS_2", WM8994_AIF1_DAC2_FILTERS_2 },
- {"AIF2_ADC_LEFT_VOLUME", WM8994_AIF2_ADC_LEFT_VOLUME },
- {"AIF2_ADC_RIGHT_VOLUME", WM8994_AIF2_ADC_RIGHT_VOLUME },
- {"AIF2_DAC_LEFT_VOLUME", WM8994_AIF2_DAC_LEFT_VOLUME },
- {"AIF2_DAC_RIGHT_VOLUME", WM8994_AIF2_DAC_RIGHT_VOLUME },
- {"AIF2_DAC_FILTERS_2", WM8994_AIF2_DAC_FILTERS_2 },
- {"DAC1_LEFT_VOLUME", WM8994_DAC1_LEFT_VOLUME },
- {"DAC1_RIGHT_VOLUME", WM8994_DAC1_RIGHT_VOLUME },
- {"DAC2_LEFT_VOLUME", WM8994_DAC2_LEFT_VOLUME },
- {"DAC2_RIGHT_VOLUME", WM8994_DAC2_RIGHT_VOLUME },
- {"POWER_MANAGEMENT_1", WM8994_POWER_MANAGEMENT_1 },
- {"POWER_MANAGEMENT_3", WM8994_POWER_MANAGEMENT_3 },
- {"ANTIPOP_2", WM8994_ANTIPOP_2 },
- {"AIF1_CLOCKING_1", WM8994_AIF1_CLOCKING_1 },
- {"FLL1_CONTROL_1", WM8994_FLL1_CONTROL_1 },
- {"FLL1_CONTROL_2", WM8994_FLL1_CONTROL_2 },
- {"FLL1_CONTROL_3", WM8994_FLL1_CONTROL_3 },
- {"FLL1_CONTROL_4", WM8994_FLL1_CONTROL_4 },
- {"FLL1_CONTROL_5", WM8994_FLL1_CONTROL_5 },
- {"AIF1_MASTER_SLAVE", WM8994_AIF1_MASTER_SLAVE },
- {"AIF1_BCLK", WM8994_AIF1_BCLK },
- {"AIF1DAC_LRCLK", WM8994_AIF1DAC_LRCLK },
- {"AIF1_DAC1_FILTERS_1", WM8994_AIF1_DAC1_FILTERS_1 },
-};
-#endif
-
-typedef struct {
- I2CSlave i2c;
- uint16_t i2c_addr;
- int i2c_idx;
-
- uint16_t reg[WM8994_REGS_NUM];
-
- void (*data_req)(void *, int);
- void *opaque;
-
- SWVoiceOut *dac_voice;
- QEMUSoundCard card;
-
- bool active;
-} WM8994State;
-
-static struct {
- int val, rate;
-} srs[] = {
- { 0, 8000 },
- { 1, 11025 },
- { 2, 12000 },
- { 3, 16000 },
- { 4, 22050 },
- { 5, 24000 },
- { 6, 32000 },
- { 7, 44100 },
- { 8, 48000 },
- { 9, 88200 },
- { 10, 96000 },
-};
-
-#ifdef DEBUG_WM8994
-static char wm8994_regname_buff[50];
-static const char *wm8994_regname(WM8994State *s,
- uint16_t address)
-{
- int i;
-
- for (i = 0; i < ARRAY_SIZE(wm8994_regs); i++) {
- if (address == wm8994_regs[i].address) {
- return wm8994_regs[i].name;
- }
- }
-
- snprintf(
- &wm8994_regname_buff[0],
- sizeof(wm8994_regname_buff),
- "reg(%.4X)",
- (unsigned int)address);
-
- return &wm8994_regname_buff[0];
-}
-#endif
-
-static void wm8994_update_format(WM8994State *s);
-
-static int vmstate_wm8994_post_load(void *opaque, int version)
-{
- WM8994State *s = opaque;
-
- DPRINTF("enter\n");
-
- wm8994_update_format(s);
-
- return 0;
-}
-
-static const VMStateDescription vmstate_wm8994 = {
- .name = CODEC,
- .version_id = 1,
- .minimum_version_id = 1,
- .minimum_version_id_old = 1,
- .post_load = vmstate_wm8994_post_load,
- .fields = (VMStateField[]) {
- VMSTATE_I2C_SLAVE(i2c, WM8994State),
- VMSTATE_UINT16(i2c_addr, WM8994State),
- VMSTATE_INT32(i2c_idx, WM8994State),
- VMSTATE_UINT16_ARRAY(reg, WM8994State,
- WM8994_REGS_NUM),
- VMSTATE_BOOL(active, WM8994State),
- VMSTATE_END_OF_LIST()
- }
-};
-
-static uint8_t wm8994_volume(WM8994State *s, uint16_t reg)
-{
- return (s->reg[reg] >> WM8994_SPKOUTL_VOL_SHIFT) &
- (WM8994_SPKOUTL_VOL_MASK >> WM8994_SPKOUTL_VOL_SHIFT);
-}
-
-static int wm8994_rate(WM8994State *s, uint16_t reg)
-{
- int i;
- int rate = (s->reg[reg] >> WM8994_AIF1_SR_SHIFT) &
- (WM8994_AIF1_SR_MASK >> WM8994_AIF1_SR_SHIFT);
-
- for (i = 0; i < ARRAY_SIZE(srs); ++i) {
- if (rate == srs[i].val) {
- return srs[i].rate;
- }
- }
-
- return 0;
-}
-
-static audfmt_e wm8994_wl(WM8994State *s, uint16_t reg)
-{
- int wl = (s->reg[reg] >> WM8994_AIF1_WL_SHIFT) &
- (WM8994_AIF1_WL_MASK >> WM8994_AIF1_WL_SHIFT);
-
- switch (wl) {
- case 0: return AUD_FMT_S16;
- case 3: return AUD_FMT_S32;
- case 1:
- /*
- * Unsupported format (20 bits per channel), but kernel
- * sets this sometimes when not playing anything
- */
- return AUD_FMT_S16;
- case 2:
- /*
- * Unsupported format (24 bits per channel), but kernel
- * sets this sometimes when not playing anything
- */
- return AUD_FMT_S16;
- default:
- hw_error("Unknown format\n");
- }
-}
-
-static void wm8994_audio_out_cb(void *opaque, int free_b)
-{
- WM8994State *s = (WM8994State *) opaque;
-
- if (s->data_req) {
- s->data_req(s->opaque, free_b);
- }
-}
-
-static void wm8994_update_volume(WM8994State *s)
-{
- int volume_left = wm8994_volume(s, WM8994_SPEAKER_VOLUME_LEFT);
- int volume_right = wm8994_volume(s, WM8994_SPEAKER_VOLUME_RIGHT);
-
- if (s->dac_voice) {
- /* Speaker */
- AUD_set_volume_out(s->dac_voice, 1, volume_left, volume_right);
- }
-}
-
-static void wm8994_update_active(WM8994State *s)
-{
- if (s->dac_voice) {
- AUD_set_active_out(s->dac_voice, s->active);
- }
-}
-
-static void wm8994_update_format(WM8994State *s)
-{
- struct audsettings out_fmt;
-
- if (s->dac_voice) {
- AUD_set_active_out(s->dac_voice, 0);
- }
-
- /* Setup output */
- out_fmt.endianness = 0;
- out_fmt.nchannels = 2;
- out_fmt.freq = wm8994_rate(s, WM8994_AIF1_RATE);
- out_fmt.fmt = wm8994_wl(s, WM8994_AIF1_CONTROL_1);
-
- s->dac_voice =
- AUD_open_out(&s->card,
- s->dac_voice,
- CODEC ".speaker",
- s,
- wm8994_audio_out_cb,
- &out_fmt);
-
- wm8994_update_volume(s);
-
- wm8994_update_active(s);
-}
-
-static void wm8994_reset(DeviceState *dev)
-{
- WM8994State *s = FROM_I2C_SLAVE(WM8994State, I2C_SLAVE_FROM_QDEV(dev));
-
- DPRINTF("enter\n");
-
- s->i2c_addr = 0;
- s->i2c_idx = 0;
- s->active = 0;
-
- memset(s->reg, 0, sizeof(s->reg));
- s->reg[WM8994_SOFTWARE_RESET] = 0x8994;
- s->reg[WM8994_POWER_MANAGEMENT_2] = 0x6000;
- s->reg[WM8994_SPEAKER_VOLUME_LEFT] = (0x79 << WM8994_SPKOUTL_VOL_SHIFT);
- s->reg[WM8994_SPEAKER_VOLUME_RIGHT] = (0x79 << WM8994_SPKOUTL_VOL_SHIFT);
- s->reg[WM8994_AIF1_RATE] = (srs[0].val << WM8994_AIF1_SR_SHIFT);
- s->reg[WM8994_AIF1_CONTROL_1] = (0x0 << WM8994_AIF1_WL_SHIFT);
-
- wm8994_update_format(s);
-}
-
-static int wm8994_tx(I2CSlave *i2c, uint8_t data)
-{
- WM8994State *s = (WM8994State *) i2c;
-
- if (s->i2c_idx < sizeof(s->i2c_addr)) {
- s->i2c_addr |=
- (uint16_t)data << ((sizeof(s->i2c_addr) - s->i2c_idx - 1) * 8);
- } else {
- uint16_t offset = s->i2c_idx - sizeof(s->i2c_addr);
- uint16_t addr = s->i2c_addr + (offset / 2);
-
- offset %= 2;
-
- if (addr >= WM8994_REGS_NUM) {
- hw_error("illegal write offset 0x%X\n", s->i2c_addr + offset);
- } else {
- s->reg[addr] &= ~(0xFF << ((1 - offset) * 8));
- s->reg[addr] |= (uint16_t)data << ((1 - offset) * 8);
-
- if (offset == 1) {
- DPRINTF("0x%.4X -> %s\n",
- (unsigned int)s->reg[addr],
- wm8994_regname(s, addr));
- switch (addr) {
- case WM8994_SOFTWARE_RESET:
- wm8994_reset(&s->i2c.qdev);
- break;
-
- case WM8994_SPEAKER_VOLUME_LEFT:
- case WM8994_SPEAKER_VOLUME_RIGHT:
- wm8994_update_volume(s);
- break;
-
- case WM8994_AIF1_RATE:
- case WM8994_AIF1_CONTROL_1:
- wm8994_update_format(s);
- break;
-
- default:
- break;
- }
- }
- }
- }
-
- ++s->i2c_idx;
-
- return 1;
-}
-
-static int wm8994_rx(I2CSlave *i2c)
-{
- WM8994State *s = (WM8994State *) i2c;
-
- if (s->i2c_idx >= sizeof(uint16_t)) {
- DPRINTF("too much data requested (%i bytes)\n", (s->i2c_idx + 1));
-
- return 0;
- }
-
- if (s->i2c_addr < WM8994_REGS_NUM) {
- int ret = (s->reg[s->i2c_addr] >> ((1 - s->i2c_idx) * 8)) & 0xFF;
-
- if (s->i2c_idx == (sizeof(uint16_t) - 1)) {
- DPRINTF("%s -> 0x%.4X\n",
- wm8994_regname(s, s->i2c_addr),
- (unsigned int)s->reg[s->i2c_addr]);
- }
-
- ++s->i2c_idx;
-
- return ret;
- } else {
- hw_error(
- "wm8994: illegal read offset 0x%x\n", s->i2c_addr + s->i2c_idx);
- }
-}
-
-static void wm8994_event(I2CSlave *i2c, enum i2c_event event)
-{
- WM8994State *s = (WM8994State *) i2c;
-
- switch (event) {
- case I2C_START_SEND:
- s->i2c_addr = 0;
- case I2C_START_RECV:
- s->i2c_idx = 0;
- break;
- default:
- break;
- }
-}
-
-void wm8994_set_active(DeviceState *dev, bool active)
-{
- WM8994State *s = FROM_I2C_SLAVE(WM8994State, I2C_SLAVE_FROM_QDEV(dev));
-
- DPRINTF("enter %d\n", active);
-
- s->active = active;
-
- wm8994_update_active(s);
-}
-
-void wm8994_data_req_set(DeviceState *dev,
- void (*data_req)(void*, int),
- void *opaque)
-{
- WM8994State *s = FROM_I2C_SLAVE(WM8994State, I2C_SLAVE_FROM_QDEV(dev));
-
- s->data_req = data_req;
- s->opaque = opaque;
-}
-
-int wm8994_dac_write(DeviceState *dev, void *buf, int num_bytes)
-{
- WM8994State *s = FROM_I2C_SLAVE(WM8994State, I2C_SLAVE_FROM_QDEV(dev));
-
- int sent = 0;
-
- if (!s->dac_voice) {
- return 0;
- }
-
- while (sent < num_bytes) {
- int ret = AUD_write(s->dac_voice,
- (uint8_t *)buf + sent,
- num_bytes - sent);
-
- sent += ret;
-
- if (ret == 0) {
- break;
- }
- }
-
- return sent;
-}
-
-static int wm8994_init(I2CSlave *i2c)
-{
- WM8994State *s = FROM_I2C_SLAVE(WM8994State, i2c);
-
- AUD_register_card(CODEC, &s->card);
-
- return 0;
-}
-
-static void wm8994_class_init(ObjectClass *klass, void *data)
-{
- DeviceClass *dc = DEVICE_CLASS(klass);
- I2CSlaveClass *sc = I2C_SLAVE_CLASS(klass);
-
- sc->init = wm8994_init;
- sc->event = wm8994_event;
- sc->recv = wm8994_rx;
- sc->send = wm8994_tx;
- dc->reset = wm8994_reset;
- dc->vmsd = &vmstate_wm8994;
-}
-
-static TypeInfo wm8994_info = {
- .name = "wm8994",
- .parent = TYPE_I2C_SLAVE,
- .instance_size = sizeof(WM8994State),
- .class_init = wm8994_class_init,
-};
-
-static void wm8994_register_types(void)
-{
- type_register_static(&wm8994_info);
-}
-
-type_init(wm8994_register_types)
+++ /dev/null
-#ifndef QEMU_HW_WM8994_H
-#define QEMU_HW_WM8994_H
-
-#include "qdev.h"
-
-void wm8994_set_active(DeviceState *dev, bool active);
-
-void wm8994_data_req_set(DeviceState *dev,
- void (*data_req)(void*, int),
- void *opaque);
-
-int wm8994_dac_write(DeviceState *dev, void *buf, int num_bytes);
-
-#endif