From: Stanislav Vorobiov Date: Fri, 20 Jun 2014 13:06:34 +0000 (+0400) Subject: exynos4210: remove old files X-Git-Tag: Tizen_Studio_1.3_Release_p2.3.1~228^2^2~125 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=refs%2Fchanges%2F96%2F23296%2F1;p=sdk%2Femulator%2Fqemu.git exynos4210: remove old files these files are now in hw/* Change-Id: I02513ae9d951d62ea932ebf2c5496dce1f2a855a Signed-off-by: Stanislav Vorobiov --- diff --git a/hw/exynos4210.c b/hw/exynos4210.c deleted file mode 100644 index 00d4db8871..0000000000 --- a/hw/exynos4210.c +++ /dev/null @@ -1,338 +0,0 @@ -/* - * Samsung exynos4210 SoC emulation - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. - * Maksim Kozlov - * Evgeny Voevodin - * Igor Mitsyanko - * - * 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 . - * - */ - -#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 */ - 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; -} diff --git a/hw/exynos4210.h b/hw/exynos4210.h deleted file mode 100644 index 6e96507def..0000000000 --- a/hw/exynos4210.h +++ /dev/null @@ -1,192 +0,0 @@ -/* - * Samsung exynos4210 SoC emulation - * - * Copyright (c) 2011 Samsung Electronics Co., Ltd. All rights reserved. - * Maksim Kozlov - * Evgeny Voevodin - * Igor Mitsyanko - * - * - * 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 . - * - */ - - -#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_ */ diff --git a/hw/exynos4210_audio.c b/hw/exynos4210_audio.c deleted file mode 100644 index c5004ab67b..0000000000 --- a/hw/exynos4210_audio.c +++ /dev/null @@ -1,149 +0,0 @@ -/* - * Samsung exynos4210 Audio driver - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * Vorobiov Stanislav - * - * 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 . - * - */ - -#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) diff --git a/hw/exynos4210_cmu.c b/hw/exynos4210_cmu.c deleted file mode 100644 index bab2ceb207..0000000000 --- a/hw/exynos4210_cmu.c +++ /dev/null @@ -1,1499 +0,0 @@ -/* - * exynos4210 Clock Management Units (CMUs) Emulation - * - * Copyright (C) 2011 Samsung Electronics Co Ltd. - * Maksim Kozlov, - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of 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 . - * - */ - -#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 _CON0 register */ -#define PLL_ENABLE_SHIFT 31 -#define PLL_ENABLE_MASK 0x80000000 /* [31] bit */ -#define PLL_LOCKED_MASK 0x20000000 /* [29] bit */ -#define PLL_MDIV_SHIFT 16 -#define PLL_MDIV_MASK 0x03FF0000 /* [25:16] bits */ -#define PLL_PDIV_SHIFT 8 -#define PLL_PDIV_MASK 0x00003F00 /* [13:8] bits */ -#define PLL_SDIV_SHIFT 0 -#define PLL_SDIV_MASK 0x00000007 /* [2:0] bits */ - -/* - * Offset in CLK_DIV_CPU0 register - * for DIVAPLL clock divider ratio - */ -#define APLL_RATIO_SHIFT 24 -#define APLL_RATIO_MASK 0x07000000 /* [26:24] bits */ - -/* - * Offset in CLK_DIV_TOP register - * for DIVACLK_100 clock divider ratio - */ -#define ACLK_100_RATIO_SHIFT 4 -#define ACLK_100_RATIO_MASK 0x000000f0 /* [7:4] bits */ - -/* Offset in CLK_SRC_TOP0 register */ -#define MUX_ACLK_100_SEL_SHIFT 16 - -/* - * Offsets in CLK_SRC_PERIL0 register - * for clock sources of UARTs - */ -#define UART0_SEL_SHIFT 0 -#define UART1_SEL_SHIFT 4 -#define UART2_SEL_SHIFT 8 -#define UART3_SEL_SHIFT 12 -#define UART4_SEL_SHIFT 16 -/* - * Offsets in CLK_DIV_PERIL0 register - * for clock divider of UARTs - */ -#define UART0_DIV_SHIFT 0 -#define UART1_DIV_SHIFT 4 -#define UART2_DIV_SHIFT 8 -#define UART3_DIV_SHIFT 12 -#define UART4_DIV_SHIFT 16 - -#define SOURCES_NUMBER 9 - -typedef struct ClockChangeEntry { - QTAILQ_ENTRY(ClockChangeEntry) entry; - ClockChangeHandler *func; - void *opaque; -} ClockChangeEntry; - -#define TYPE_EXYNOS4210_CMU "exynos4210.cmu" -#define TYPE_EXYNOS4210_CLOCK "exynos4210.clock" - -typedef struct { - - const char *name; - int32_t id; - uint64_t rate; - - /* Current source clock */ - int32_t src_id; - /* - * Available sources. Their order must correspond to CLK_SRC_ register - */ - int32_t src_ids[SOURCES_NUMBER]; - - uint32_t src_reg; /* Offset of CLK_SRC_<*> register */ - uint32_t div_reg; /* Offset of CLK_DIV_<*> register */ - - /* - * Shift for MUX__SEL value which is stored - * in appropriate CLK_MUX_STAT_ register - */ - uint8_t mux_shift; - - /* - * Shift for _RATIO value which is stored - * in appropriate CLK_DIV_ register - */ - uint8_t div_shift; - - /* Which CMU controls this clock */ - int32_t cmu_id; - - QTAILQ_HEAD(, ClockChangeEntry) clock_change_handler; - -} Exynos4210ClockState; - - -typedef struct { - - SysBusDevice busdev; - MemoryRegion iomem; - - /* registers values */ - uint32_t reg[EXYNOS4210_CMU_REGS_MEM_SIZE / sizeof(uint32_t)]; - - /* which CMU it is */ - Exynos4210Cmu cmu_id; - - /* registers information for debugging and resetting */ - 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) diff --git a/hw/exynos4210_fimd.c b/hw/exynos4210_fimd.c deleted file mode 100644 index 84288a436e..0000000000 --- a/hw/exynos4210_fimd.c +++ /dev/null @@ -1,1975 +0,0 @@ -/* - * 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 - * - * Contributed by Mitsyanko Igor - * - * 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 . - */ - -#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) diff --git a/hw/exynos4210_g3d.c b/hw/exynos4210_g3d.c deleted file mode 100644 index b66860ef8c..0000000000 --- a/hw/exynos4210_g3d.c +++ /dev/null @@ -1,833 +0,0 @@ -/* - * Samsung exynos4210 MALI400 gpu (G3D) emulation - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. - * All rights reserved. - * - * Mitsyanko Igor - * - * 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 . - */ - -#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) diff --git a/hw/exynos4210_gic.c b/hw/exynos4210_gic.c deleted file mode 100644 index 4ad0bfb3d8..0000000000 --- a/hw/exynos4210_gic.c +++ /dev/null @@ -1,477 +0,0 @@ -/* - * Samsung exynos4210 GIC implementation. Based on hw/arm_gic.c - * - * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd. - * All rights reserved. - * - * Evgeny Voevodin - * - * 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 . - */ - -#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) diff --git a/hw/exynos4210_i2s.c b/hw/exynos4210_i2s.c deleted file mode 100644 index 705643f355..0000000000 --- a/hw/exynos4210_i2s.c +++ /dev/null @@ -1,592 +0,0 @@ -/* - * Samsung exynos4210 I2S driver - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * Vorobiov Stanislav - * - * 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 . - * - */ - -#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) diff --git a/hw/exynos4210_i2s.h b/hw/exynos4210_i2s.h deleted file mode 100644 index 86b9c30e39..0000000000 --- a/hw/exynos4210_i2s.h +++ /dev/null @@ -1,57 +0,0 @@ -#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 diff --git a/hw/exynos4210_uart.c b/hw/exynos4210_uart.c deleted file mode 100644 index 155abdb640..0000000000 --- a/hw/exynos4210_uart.c +++ /dev/null @@ -1,707 +0,0 @@ -/* - * Exynos4210 UART Emulation - * - * Copyright (C) 2011 Samsung Electronics Co Ltd. - * Maksim Kozlov, - * - * This program is free software; you can redistribute it and/or modify it - * under the terms of the GNU General Public License as published by the - * Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, but WITHOUT - * ANY WARRANTY; without even the implied warranty of 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 . - * - */ - -#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) diff --git a/hw/wm8994.c b/hw/wm8994.c deleted file mode 100644 index 9d3b9a0f30..0000000000 --- a/hw/wm8994.c +++ /dev/null @@ -1,644 +0,0 @@ -/* - * Samsung exynos4210 wm8994 driver - * - * Copyright (c) 2012 Samsung Electronics Co., Ltd. - * Vorobiov Stanislav - * - * 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 . - * - */ - -#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) diff --git a/hw/wm8994.h b/hw/wm8994.h deleted file mode 100644 index c4053f6977..0000000000 --- a/hw/wm8994.h +++ /dev/null @@ -1,14 +0,0 @@ -#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