7072f586c3012813cacf6c1703b5f1efdce51dca
[sdk/emulator/qemu.git] / tizen / src / hw / maru_overlay.c
1 /*
2  * Maru overlay device for VGA
3  *
4  * Copyright (C) 2011 - 2013 Samsung Electronics Co., Ltd. All rights reserved.
5  *
6  * Contact:
7  * JinHyung Jo <jinhyung.jo@samsung.com>
8  * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
9  * DongKyun Yun
10  * DoHyung Hong
11  * Hyunjun Son
12  *
13  * This program is free software; you can redistribute it and/or
14  * modify it under the terms of the GNU General Public License
15  * as published by the Free Software Foundation; either version 2
16  * of the License, or (at your option) any later version.
17  *
18  * This program is distributed in the hope that it will be useful,
19  * but WITHOUT ANY WARRANTY; without even the implied warranty of
20  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21  * GNU General Public License for more details.
22  *
23  * You should have received a copy of the GNU General Public License
24  * along with this program; if not, write to the Free Software
25  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston,
26  * MA  02110-1301, USA.
27  *
28  * Contributors:
29  * - S-Core Co., Ltd
30  *
31  */
32
33 #include "pc.h"
34 #include "pci.h"
35 #include "maru_device_ids.h"
36 #include "maru_overlay.h"
37 #include "debug_ch.h"
38
39 MULTI_DEBUG_CHANNEL(qemu, maru_overlay);
40
41 #define QEMU_DEV_NAME       "MARU_OVERLAY"
42
43 #define OVERLAY_MEM_SIZE    (8192 * 1024)   /* 4MB(overlay0) + 4MB(overlay1) */
44 #define OVERLAY_REG_SIZE    256
45 #define OVERLAY1_REG_OFFSET (OVERLAY_REG_SIZE / 2)
46
47
48 enum {
49     OVERLAY_POWER    = 0x00,
50     OVERLAY_POSITION = 0x04,    /* left top position */
51     OVERLAY_SIZE     = 0x08,    /* width and height */
52 };
53
54 uint8_t *overlay_ptr;
55
56 uint8_t overlay0_power;
57 uint16_t overlay0_left;
58 uint16_t overlay0_top;
59 uint16_t overlay0_width;
60 uint16_t overlay0_height;
61
62 uint8_t overlay1_power;
63 uint16_t overlay1_left;
64 uint16_t overlay1_top;
65 uint16_t overlay1_width;
66 uint16_t overlay1_height;
67
68 typedef struct OverlayState {
69     PCIDevice       dev;
70
71     MemoryRegion    mem_addr;
72     MemoryRegion    mmio_addr;
73 } OverlayState;
74
75
76 static uint64_t overlay_reg_read(void *opaque,
77                                  target_phys_addr_t addr,
78                                  unsigned size)
79 {
80     switch (addr) {
81     case OVERLAY_POWER:
82         TRACE("GET => overlay0 power status(%d)\n", overlay0_power);
83         return overlay0_power;
84         break;
85     case OVERLAY_POSITION:
86         TRACE("GET => overlay0 position, left(%d):top(%d)\n",
87               overlay0_left, overlay0_top);
88         return overlay0_left | overlay0_top << 16;
89         break;
90     case OVERLAY_SIZE:
91         TRACE("GET => overlay0 size, width(%d):height(%d)\n",
92               overlay0_width, overlay0_height);
93         return overlay0_width | overlay0_height << 16;
94         break;
95     case OVERLAY1_REG_OFFSET + OVERLAY_POWER:
96         TRACE("GET => overlay1 power status(%d)\n", overlay1_power);
97         return overlay1_power;
98         break;
99     case OVERLAY1_REG_OFFSET + OVERLAY_POSITION:
100         TRACE("GET => overlay1 position, left(%d):top(%d)\n",
101               overlay1_left, overlay1_top);
102         return overlay1_left | overlay1_top << 16;
103         break;
104     case OVERLAY1_REG_OFFSET + OVERLAY_SIZE:
105         TRACE("GET => overlay1 size, width(%d):height(%d)\n",
106               overlay1_width, overlay1_height);
107         return overlay1_width | overlay1_height << 16;
108         break;
109     default:
110         ERR("wrong overlay register read - addr : %d\n", (int)addr);
111         break;
112     }
113
114     return 0;
115 }
116
117 static void overlay_reg_write(void *opaque,
118                               target_phys_addr_t addr,
119                               uint64_t val,
120                               unsigned size)
121 {
122     switch (addr) {
123     case OVERLAY_POWER:
124         overlay0_power = val;
125         TRACE("SET => overlay0 power status(%d)\n", overlay0_power);
126         if (!overlay0_power) {
127             /* clear the last overlay area. */
128             memset(overlay_ptr, 0x00, (OVERLAY_MEM_SIZE / 2));
129             overlay0_left = overlay0_top = overlay0_width = overlay0_height = 0;
130             TRACE("clear the last overlay0 area\n");
131         }
132         break;
133     case OVERLAY_POSITION:
134         overlay0_left = val & 0xFFFF;
135         overlay0_top = val >> 16;
136         TRACE("SET => overlay0 position, left(%d):top(%d)\n",
137               overlay0_left, overlay0_top);
138         break;
139     case OVERLAY_SIZE:
140         overlay0_width = val & 0xFFFF;
141         overlay0_height = val >> 16;
142         TRACE("SET => overlay0 size, width(%d):height(%d)\n",
143               overlay0_width, overlay0_height);
144         break;
145     case OVERLAY1_REG_OFFSET + OVERLAY_POWER:
146         overlay1_power = val;
147         TRACE("SET => overlay1 power status(%d)\n", overlay1_power);
148         if (!overlay1_power) {
149             /* clear the last overlay area. */
150             memset(overlay_ptr + OVERLAY1_REG_OFFSET,
151                    0x00, (OVERLAY_MEM_SIZE / 2));
152             overlay1_left = overlay1_top = overlay1_width = overlay1_height = 0;
153             TRACE("clear the last overlay1 area\n");
154         }
155         break;
156     case OVERLAY1_REG_OFFSET + OVERLAY_POSITION:
157         overlay1_left = val & 0xFFFF;
158         overlay1_top = val >> 16;
159         TRACE("SET => overlay1 position, left(%d):top(%d)\n",
160               overlay1_left, overlay1_top);
161         break;
162     case OVERLAY1_REG_OFFSET + OVERLAY_SIZE:
163         overlay1_width = val & 0xFFFF;
164         overlay1_height = val >> 16;
165         TRACE("SET => overlay1 size, width(%d):height(%d)\n",
166               overlay1_width, overlay1_height);
167         break;
168     default:
169         ERR("wrong overlay register write - addr : %d\n", (int)addr);
170         break;
171     }
172 }
173
174 static const MemoryRegionOps overlay_mmio_ops = {
175     .read = overlay_reg_read,
176     .write = overlay_reg_write,
177     .endianness = DEVICE_LITTLE_ENDIAN,
178 };
179
180 static int overlay_initfn(PCIDevice *dev)
181 {
182     OverlayState *s = DO_UPCAST(OverlayState, dev, dev);
183     uint8_t *pci_conf = s->dev.config;
184
185     pci_config_set_vendor_id(pci_conf, PCI_VENDOR_ID_TIZEN);
186     pci_config_set_device_id(pci_conf, PCI_DEVICE_ID_VIRTUAL_OVERLAY);
187     pci_config_set_class(pci_conf, PCI_CLASS_DISPLAY_OTHER);
188
189     memory_region_init_ram(&s->mem_addr, "maru_overlay.ram", OVERLAY_MEM_SIZE);
190     overlay_ptr = memory_region_get_ram_ptr(&s->mem_addr);
191
192     memory_region_init_io(&s->mmio_addr, &overlay_mmio_ops,
193                           s,
194                           "maru_overlay_mmio",
195                           OVERLAY_REG_SIZE);
196
197     /* setup memory space */
198     /* memory #0 device memory (overlay surface) */
199     /* memory #1 memory-mapped I/O */
200     pci_register_bar(&s->dev, 0, PCI_BASE_ADDRESS_MEM_PREFETCH, &s->mem_addr);
201     pci_register_bar(&s->dev, 1, PCI_BASE_ADDRESS_SPACE_MEMORY, &s->mmio_addr);
202
203     return 0;
204 }
205
206 DeviceState *pci_maru_overlay_init(PCIBus *bus)
207 {
208     INFO("Maru overlay was initailized!\n");
209     return &pci_create_simple(bus, -1, QEMU_DEV_NAME)->qdev;
210 }
211
212 static void overlay_classinit(ObjectClass *klass, void *data)
213 {
214     PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
215
216     k->no_hotplug = 1;
217     k->init = overlay_initfn;
218 }
219
220 static TypeInfo overlay_info = {
221     .name          = QEMU_DEV_NAME,
222     .parent        = TYPE_PCI_DEVICE,
223     .instance_size = sizeof(OverlayState),
224     .class_init    = overlay_classinit,
225 };
226
227 static void overlay_register_types(void)
228 {
229     type_register_static(&overlay_info);
230 }
231
232 type_init(overlay_register_types);