1c3d2689dSbalrog /* 2c3d2689dSbalrog * OMAP LCD controller. 3c3d2689dSbalrog * 4c3d2689dSbalrog * Copyright (C) 2006-2007 Andrzej Zaborowski <balrog@zabor.org> 5c3d2689dSbalrog * 6c3d2689dSbalrog * This program is free software; you can redistribute it and/or 7c3d2689dSbalrog * modify it under the terms of the GNU General Public License as 8c3d2689dSbalrog * published by the Free Software Foundation; either version 2 of 9c3d2689dSbalrog * the License, or (at your option) any later version. 10c3d2689dSbalrog * 11c3d2689dSbalrog * This program is distributed in the hope that it will be useful, 12c3d2689dSbalrog * but WITHOUT ANY WARRANTY; without even the implied warranty of 13c3d2689dSbalrog * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 14c3d2689dSbalrog * GNU General Public License for more details. 15c3d2689dSbalrog * 16fad6cb1aSaurel32 * You should have received a copy of the GNU General Public License along 178167ee88SBlue Swirl * with this program; if not, see <http://www.gnu.org/licenses/>. 18c3d2689dSbalrog */ 1983c9f4caSPaolo Bonzini #include "hw/hw.h" 2028ecbaeeSPaolo Bonzini #include "ui/console.h" 210d09e41aSPaolo Bonzini #include "hw/arm/omap.h" 2247b43a1fSPaolo Bonzini #include "framebuffer.h" 2328ecbaeeSPaolo Bonzini #include "ui/pixel_ops.h" 24c3d2689dSbalrog 25c3d2689dSbalrog struct omap_lcd_panel_s { 2675c9d6c2SAvi Kivity MemoryRegion *sysmem; 2730af1ec7SBenoît Canet MemoryRegion iomem; 28c1076c3eSPaolo Bonzini MemoryRegionSection fbsection; 29c3d2689dSbalrog qemu_irq irq; 30c78f7137SGerd Hoffmann QemuConsole *con; 31c3d2689dSbalrog 32c3d2689dSbalrog int plm; 33c3d2689dSbalrog int tft; 34c3d2689dSbalrog int mono; 35c3d2689dSbalrog int enable; 36c3d2689dSbalrog int width; 37c3d2689dSbalrog int height; 38c3d2689dSbalrog int interrupts; 39c3d2689dSbalrog uint32_t timing[3]; 40c3d2689dSbalrog uint32_t subpanel; 41c3d2689dSbalrog uint32_t ctrl; 42c3d2689dSbalrog 43c3d2689dSbalrog struct omap_dma_lcd_channel_s *dma; 44c3d2689dSbalrog uint16_t palette[256]; 45c3d2689dSbalrog int palette_done; 46c3d2689dSbalrog int frame_done; 47c3d2689dSbalrog int invalidate; 48c3d2689dSbalrog int sync_error; 49c3d2689dSbalrog }; 50c3d2689dSbalrog 51c3d2689dSbalrog static void omap_lcd_interrupts(struct omap_lcd_panel_s *s) 52c3d2689dSbalrog { 53c3d2689dSbalrog if (s->frame_done && (s->interrupts & 1)) { 54c3d2689dSbalrog qemu_irq_raise(s->irq); 55c3d2689dSbalrog return; 56c3d2689dSbalrog } 57c3d2689dSbalrog 58c3d2689dSbalrog if (s->palette_done && (s->interrupts & 2)) { 59c3d2689dSbalrog qemu_irq_raise(s->irq); 60c3d2689dSbalrog return; 61c3d2689dSbalrog } 62c3d2689dSbalrog 63c3d2689dSbalrog if (s->sync_error) { 64c3d2689dSbalrog qemu_irq_raise(s->irq); 65c3d2689dSbalrog return; 66c3d2689dSbalrog } 67c3d2689dSbalrog 68c3d2689dSbalrog qemu_irq_lower(s->irq); 69c3d2689dSbalrog } 70c3d2689dSbalrog 71714fa308Spbrook #define draw_line_func drawfn 72c3d2689dSbalrog 73c3d2689dSbalrog #define DEPTH 8 7447b43a1fSPaolo Bonzini #include "omap_lcd_template.h" 75c3d2689dSbalrog #define DEPTH 15 7647b43a1fSPaolo Bonzini #include "omap_lcd_template.h" 77c3d2689dSbalrog #define DEPTH 16 7847b43a1fSPaolo Bonzini #include "omap_lcd_template.h" 79c3d2689dSbalrog #define DEPTH 32 8047b43a1fSPaolo Bonzini #include "omap_lcd_template.h" 81c3d2689dSbalrog 82714fa308Spbrook static draw_line_func draw_line_table2[33] = { 83b9d38e95SBlue Swirl [0 ... 32] = NULL, 84c3d2689dSbalrog [8] = draw_line2_8, 85c3d2689dSbalrog [15] = draw_line2_15, 86c3d2689dSbalrog [16] = draw_line2_16, 87c3d2689dSbalrog [32] = draw_line2_32, 88714fa308Spbrook }, draw_line_table4[33] = { 89b9d38e95SBlue Swirl [0 ... 32] = NULL, 90c3d2689dSbalrog [8] = draw_line4_8, 91c3d2689dSbalrog [15] = draw_line4_15, 92c3d2689dSbalrog [16] = draw_line4_16, 93c3d2689dSbalrog [32] = draw_line4_32, 94714fa308Spbrook }, draw_line_table8[33] = { 95b9d38e95SBlue Swirl [0 ... 32] = NULL, 96c3d2689dSbalrog [8] = draw_line8_8, 97c3d2689dSbalrog [15] = draw_line8_15, 98c3d2689dSbalrog [16] = draw_line8_16, 99c3d2689dSbalrog [32] = draw_line8_32, 100714fa308Spbrook }, draw_line_table12[33] = { 101b9d38e95SBlue Swirl [0 ... 32] = NULL, 102c3d2689dSbalrog [8] = draw_line12_8, 103c3d2689dSbalrog [15] = draw_line12_15, 104c3d2689dSbalrog [16] = draw_line12_16, 105c3d2689dSbalrog [32] = draw_line12_32, 106714fa308Spbrook }, draw_line_table16[33] = { 107b9d38e95SBlue Swirl [0 ... 32] = NULL, 108c3d2689dSbalrog [8] = draw_line16_8, 109c3d2689dSbalrog [15] = draw_line16_15, 110c3d2689dSbalrog [16] = draw_line16_16, 111c3d2689dSbalrog [32] = draw_line16_32, 112c3d2689dSbalrog }; 113c3d2689dSbalrog 1149596ebb7Spbrook static void omap_update_display(void *opaque) 115c3d2689dSbalrog { 116c3d2689dSbalrog struct omap_lcd_panel_s *omap_lcd = (struct omap_lcd_panel_s *) opaque; 117c78f7137SGerd Hoffmann DisplaySurface *surface = qemu_console_surface(omap_lcd->con); 118714fa308Spbrook draw_line_func draw_line; 119714fa308Spbrook int size, height, first, last; 120714fa308Spbrook int width, linesize, step, bpp, frame_offset; 121a8170e5eSAvi Kivity hwaddr frame_base; 122c3d2689dSbalrog 123c78f7137SGerd Hoffmann if (!omap_lcd || omap_lcd->plm == 1 || !omap_lcd->enable || 124c78f7137SGerd Hoffmann !surface_bits_per_pixel(surface)) { 125c3d2689dSbalrog return; 126c78f7137SGerd Hoffmann } 127c3d2689dSbalrog 128c3d2689dSbalrog frame_offset = 0; 129c3d2689dSbalrog if (omap_lcd->plm != 2) { 130714fa308Spbrook cpu_physical_memory_read(omap_lcd->dma->phys_framebuffer[ 131714fa308Spbrook omap_lcd->dma->current_frame], 132714fa308Spbrook (void *)omap_lcd->palette, 0x200); 133c3d2689dSbalrog switch (omap_lcd->palette[0] >> 12 & 7) { 134c3d2689dSbalrog case 3 ... 7: 135c3d2689dSbalrog frame_offset += 0x200; 136c3d2689dSbalrog break; 137c3d2689dSbalrog default: 138c3d2689dSbalrog frame_offset += 0x20; 139c3d2689dSbalrog } 140c3d2689dSbalrog } 141c3d2689dSbalrog 142c3d2689dSbalrog /* Colour depth */ 143c3d2689dSbalrog switch ((omap_lcd->palette[0] >> 12) & 7) { 144c3d2689dSbalrog case 1: 145c78f7137SGerd Hoffmann draw_line = draw_line_table2[surface_bits_per_pixel(surface)]; 146c3d2689dSbalrog bpp = 2; 147c3d2689dSbalrog break; 148c3d2689dSbalrog 149c3d2689dSbalrog case 2: 150c78f7137SGerd Hoffmann draw_line = draw_line_table4[surface_bits_per_pixel(surface)]; 151c3d2689dSbalrog bpp = 4; 152c3d2689dSbalrog break; 153c3d2689dSbalrog 154c3d2689dSbalrog case 3: 155c78f7137SGerd Hoffmann draw_line = draw_line_table8[surface_bits_per_pixel(surface)]; 156c3d2689dSbalrog bpp = 8; 157c3d2689dSbalrog break; 158c3d2689dSbalrog 159c3d2689dSbalrog case 4 ... 7: 160c3d2689dSbalrog if (!omap_lcd->tft) 161c78f7137SGerd Hoffmann draw_line = draw_line_table12[surface_bits_per_pixel(surface)]; 162c3d2689dSbalrog else 163c78f7137SGerd Hoffmann draw_line = draw_line_table16[surface_bits_per_pixel(surface)]; 164c3d2689dSbalrog bpp = 16; 165c3d2689dSbalrog break; 166c3d2689dSbalrog 167c3d2689dSbalrog default: 168c3d2689dSbalrog /* Unsupported at the moment. */ 169c3d2689dSbalrog return; 170c3d2689dSbalrog } 171c3d2689dSbalrog 172c3d2689dSbalrog /* Resolution */ 173c3d2689dSbalrog width = omap_lcd->width; 174c78f7137SGerd Hoffmann if (width != surface_width(surface) || 175c78f7137SGerd Hoffmann omap_lcd->height != surface_height(surface)) { 176c78f7137SGerd Hoffmann qemu_console_resize(omap_lcd->con, 177c3d2689dSbalrog omap_lcd->width, omap_lcd->height); 178c78f7137SGerd Hoffmann surface = qemu_console_surface(omap_lcd->con); 179c3d2689dSbalrog omap_lcd->invalidate = 1; 180c3d2689dSbalrog } 181c3d2689dSbalrog 182c3d2689dSbalrog if (omap_lcd->dma->current_frame == 0) 183c3d2689dSbalrog size = omap_lcd->dma->src_f1_bottom - omap_lcd->dma->src_f1_top; 184c3d2689dSbalrog else 185c3d2689dSbalrog size = omap_lcd->dma->src_f2_bottom - omap_lcd->dma->src_f2_top; 186c3d2689dSbalrog 187c3d2689dSbalrog if (frame_offset + ((width * omap_lcd->height * bpp) >> 3) > size + 2) { 188c3d2689dSbalrog omap_lcd->sync_error = 1; 189c3d2689dSbalrog omap_lcd_interrupts(omap_lcd); 190c3d2689dSbalrog omap_lcd->enable = 0; 191c3d2689dSbalrog return; 192c3d2689dSbalrog } 193c3d2689dSbalrog 194c3d2689dSbalrog /* Content */ 195c3d2689dSbalrog frame_base = omap_lcd->dma->phys_framebuffer[ 196c3d2689dSbalrog omap_lcd->dma->current_frame] + frame_offset; 197c3d2689dSbalrog omap_lcd->dma->condition |= 1 << omap_lcd->dma->current_frame; 198c3d2689dSbalrog if (omap_lcd->dma->interrupts & 1) 199c3d2689dSbalrog qemu_irq_raise(omap_lcd->dma->irq); 200c3d2689dSbalrog if (omap_lcd->dma->dual) 201c3d2689dSbalrog omap_lcd->dma->current_frame ^= 1; 202c3d2689dSbalrog 203c78f7137SGerd Hoffmann if (!surface_bits_per_pixel(surface)) { 204c3d2689dSbalrog return; 205c78f7137SGerd Hoffmann } 206c3d2689dSbalrog 207714fa308Spbrook first = 0; 208c3d2689dSbalrog height = omap_lcd->height; 209c3d2689dSbalrog if (omap_lcd->subpanel & (1 << 31)) { 210c3d2689dSbalrog if (omap_lcd->subpanel & (1 << 29)) 211714fa308Spbrook first = (omap_lcd->subpanel >> 16) & 0x3ff; 212c3d2689dSbalrog else 213c3d2689dSbalrog height = (omap_lcd->subpanel >> 16) & 0x3ff; 214c3d2689dSbalrog /* TODO: fill the rest of the panel with DPD */ 215c3d2689dSbalrog } 216714fa308Spbrook 217c3d2689dSbalrog step = width * bpp >> 3; 218c78f7137SGerd Hoffmann linesize = surface_stride(surface); 219c1076c3eSPaolo Bonzini if (omap_lcd->invalidate) { 220c1076c3eSPaolo Bonzini framebuffer_update_memory_section(&omap_lcd->fbsection, 221c1076c3eSPaolo Bonzini omap_lcd->sysmem, frame_base, 222c1076c3eSPaolo Bonzini height, step); 223c1076c3eSPaolo Bonzini } 224c1076c3eSPaolo Bonzini 225c1076c3eSPaolo Bonzini framebuffer_update_display(surface, &omap_lcd->fbsection, 226c1076c3eSPaolo Bonzini width, height, 227714fa308Spbrook step, linesize, 0, 228714fa308Spbrook omap_lcd->invalidate, 229714fa308Spbrook draw_line, omap_lcd->palette, 230714fa308Spbrook &first, &last); 231c1076c3eSPaolo Bonzini 232714fa308Spbrook if (first >= 0) { 233c78f7137SGerd Hoffmann dpy_gfx_update(omap_lcd->con, 0, first, width, last - first + 1); 234c3d2689dSbalrog } 235714fa308Spbrook omap_lcd->invalidate = 0; 236c3d2689dSbalrog } 237c3d2689dSbalrog 2389596ebb7Spbrook static void omap_invalidate_display(void *opaque) { 239c3d2689dSbalrog struct omap_lcd_panel_s *omap_lcd = opaque; 240c3d2689dSbalrog omap_lcd->invalidate = 1; 241c3d2689dSbalrog } 242c3d2689dSbalrog 2439596ebb7Spbrook static void omap_lcd_update(struct omap_lcd_panel_s *s) { 244c3d2689dSbalrog if (!s->enable) { 245c3d2689dSbalrog s->dma->current_frame = -1; 246c3d2689dSbalrog s->sync_error = 0; 247c3d2689dSbalrog if (s->plm != 1) 248c3d2689dSbalrog s->frame_done = 1; 249c3d2689dSbalrog omap_lcd_interrupts(s); 250c3d2689dSbalrog return; 251c3d2689dSbalrog } 252c3d2689dSbalrog 253c3d2689dSbalrog if (s->dma->current_frame == -1) { 254c3d2689dSbalrog s->frame_done = 0; 255c3d2689dSbalrog s->palette_done = 0; 256c3d2689dSbalrog s->dma->current_frame = 0; 257c3d2689dSbalrog } 258c3d2689dSbalrog 259c3d2689dSbalrog if (!s->dma->mpu->port[s->dma->src].addr_valid(s->dma->mpu, 260c3d2689dSbalrog s->dma->src_f1_top) || 261c3d2689dSbalrog !s->dma->mpu->port[ 262c3d2689dSbalrog s->dma->src].addr_valid(s->dma->mpu, 263c3d2689dSbalrog s->dma->src_f1_bottom) || 264c3d2689dSbalrog (s->dma->dual && 265c3d2689dSbalrog (!s->dma->mpu->port[ 266c3d2689dSbalrog s->dma->src].addr_valid(s->dma->mpu, 267c3d2689dSbalrog s->dma->src_f2_top) || 268c3d2689dSbalrog !s->dma->mpu->port[ 269c3d2689dSbalrog s->dma->src].addr_valid(s->dma->mpu, 270c3d2689dSbalrog s->dma->src_f2_bottom)))) { 271c3d2689dSbalrog s->dma->condition |= 1 << 2; 272c3d2689dSbalrog if (s->dma->interrupts & (1 << 1)) 273c3d2689dSbalrog qemu_irq_raise(s->dma->irq); 274c3d2689dSbalrog s->enable = 0; 275c3d2689dSbalrog return; 276c3d2689dSbalrog } 277c3d2689dSbalrog 278714fa308Spbrook s->dma->phys_framebuffer[0] = s->dma->src_f1_top; 279714fa308Spbrook s->dma->phys_framebuffer[1] = s->dma->src_f2_top; 280c3d2689dSbalrog 281c3d2689dSbalrog if (s->plm != 2 && !s->palette_done) { 282714fa308Spbrook cpu_physical_memory_read( 283714fa308Spbrook s->dma->phys_framebuffer[s->dma->current_frame], 284714fa308Spbrook (void *)s->palette, 0x200); 285c3d2689dSbalrog s->palette_done = 1; 286c3d2689dSbalrog omap_lcd_interrupts(s); 287c3d2689dSbalrog } 288c3d2689dSbalrog } 289c3d2689dSbalrog 290a8170e5eSAvi Kivity static uint64_t omap_lcdc_read(void *opaque, hwaddr addr, 29130af1ec7SBenoît Canet unsigned size) 292c3d2689dSbalrog { 293c3d2689dSbalrog struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque; 294c3d2689dSbalrog 2958da3ff18Spbrook switch (addr) { 296c3d2689dSbalrog case 0x00: /* LCD_CONTROL */ 297c3d2689dSbalrog return (s->tft << 23) | (s->plm << 20) | 298c3d2689dSbalrog (s->tft << 7) | (s->interrupts << 3) | 299c3d2689dSbalrog (s->mono << 1) | s->enable | s->ctrl | 0xfe000c34; 300c3d2689dSbalrog 301c3d2689dSbalrog case 0x04: /* LCD_TIMING0 */ 302c3d2689dSbalrog return (s->timing[0] << 10) | (s->width - 1) | 0x0000000f; 303c3d2689dSbalrog 304c3d2689dSbalrog case 0x08: /* LCD_TIMING1 */ 305c3d2689dSbalrog return (s->timing[1] << 10) | (s->height - 1); 306c3d2689dSbalrog 307c3d2689dSbalrog case 0x0c: /* LCD_TIMING2 */ 308c3d2689dSbalrog return s->timing[2] | 0xfc000000; 309c3d2689dSbalrog 310c3d2689dSbalrog case 0x10: /* LCD_STATUS */ 311c3d2689dSbalrog return (s->palette_done << 6) | (s->sync_error << 2) | s->frame_done; 312c3d2689dSbalrog 313c3d2689dSbalrog case 0x14: /* LCD_SUBPANEL */ 314c3d2689dSbalrog return s->subpanel; 315c3d2689dSbalrog 316c3d2689dSbalrog default: 317c3d2689dSbalrog break; 318c3d2689dSbalrog } 319c3d2689dSbalrog OMAP_BAD_REG(addr); 320c3d2689dSbalrog return 0; 321c3d2689dSbalrog } 322c3d2689dSbalrog 323a8170e5eSAvi Kivity static void omap_lcdc_write(void *opaque, hwaddr addr, 32430af1ec7SBenoît Canet uint64_t value, unsigned size) 325c3d2689dSbalrog { 326c3d2689dSbalrog struct omap_lcd_panel_s *s = (struct omap_lcd_panel_s *) opaque; 327c3d2689dSbalrog 3288da3ff18Spbrook switch (addr) { 329c3d2689dSbalrog case 0x00: /* LCD_CONTROL */ 330c3d2689dSbalrog s->plm = (value >> 20) & 3; 331c3d2689dSbalrog s->tft = (value >> 7) & 1; 332c3d2689dSbalrog s->interrupts = (value >> 3) & 3; 333c3d2689dSbalrog s->mono = (value >> 1) & 1; 334c3d2689dSbalrog s->ctrl = value & 0x01cff300; 335c3d2689dSbalrog if (s->enable != (value & 1)) { 336c3d2689dSbalrog s->enable = value & 1; 337c3d2689dSbalrog omap_lcd_update(s); 338c3d2689dSbalrog } 339c3d2689dSbalrog break; 340c3d2689dSbalrog 341c3d2689dSbalrog case 0x04: /* LCD_TIMING0 */ 342c3d2689dSbalrog s->timing[0] = value >> 10; 343c3d2689dSbalrog s->width = (value & 0x3ff) + 1; 344c3d2689dSbalrog break; 345c3d2689dSbalrog 346c3d2689dSbalrog case 0x08: /* LCD_TIMING1 */ 347c3d2689dSbalrog s->timing[1] = value >> 10; 348c3d2689dSbalrog s->height = (value & 0x3ff) + 1; 349c3d2689dSbalrog break; 350c3d2689dSbalrog 351c3d2689dSbalrog case 0x0c: /* LCD_TIMING2 */ 352c3d2689dSbalrog s->timing[2] = value; 353c3d2689dSbalrog break; 354c3d2689dSbalrog 355c3d2689dSbalrog case 0x10: /* LCD_STATUS */ 356c3d2689dSbalrog break; 357c3d2689dSbalrog 358c3d2689dSbalrog case 0x14: /* LCD_SUBPANEL */ 359c3d2689dSbalrog s->subpanel = value & 0xa1ffffff; 360c3d2689dSbalrog break; 361c3d2689dSbalrog 362c3d2689dSbalrog default: 363c3d2689dSbalrog OMAP_BAD_REG(addr); 364c3d2689dSbalrog } 365c3d2689dSbalrog } 366c3d2689dSbalrog 36730af1ec7SBenoît Canet static const MemoryRegionOps omap_lcdc_ops = { 36830af1ec7SBenoît Canet .read = omap_lcdc_read, 36930af1ec7SBenoît Canet .write = omap_lcdc_write, 37030af1ec7SBenoît Canet .endianness = DEVICE_NATIVE_ENDIAN, 371c3d2689dSbalrog }; 372c3d2689dSbalrog 373c3d2689dSbalrog void omap_lcdc_reset(struct omap_lcd_panel_s *s) 374c3d2689dSbalrog { 375c3d2689dSbalrog s->dma->current_frame = -1; 376c3d2689dSbalrog s->plm = 0; 377c3d2689dSbalrog s->tft = 0; 378c3d2689dSbalrog s->mono = 0; 379c3d2689dSbalrog s->enable = 0; 380c3d2689dSbalrog s->width = 0; 381c3d2689dSbalrog s->height = 0; 382c3d2689dSbalrog s->interrupts = 0; 383c3d2689dSbalrog s->timing[0] = 0; 384c3d2689dSbalrog s->timing[1] = 0; 385c3d2689dSbalrog s->timing[2] = 0; 386c3d2689dSbalrog s->subpanel = 0; 387c3d2689dSbalrog s->palette_done = 0; 388c3d2689dSbalrog s->frame_done = 0; 389c3d2689dSbalrog s->sync_error = 0; 390c3d2689dSbalrog s->invalidate = 1; 391c3d2689dSbalrog s->subpanel = 0; 392c3d2689dSbalrog s->ctrl = 0; 393c3d2689dSbalrog } 394c3d2689dSbalrog 395380cd056SGerd Hoffmann static const GraphicHwOps omap_ops = { 396380cd056SGerd Hoffmann .invalidate = omap_invalidate_display, 397380cd056SGerd Hoffmann .gfx_update = omap_update_display, 398380cd056SGerd Hoffmann }; 399380cd056SGerd Hoffmann 40030af1ec7SBenoît Canet struct omap_lcd_panel_s *omap_lcdc_init(MemoryRegion *sysmem, 401a8170e5eSAvi Kivity hwaddr base, 40230af1ec7SBenoît Canet qemu_irq irq, 40330af1ec7SBenoît Canet struct omap_dma_lcd_channel_s *dma, 40430af1ec7SBenoît Canet omap_clk clk) 405c3d2689dSbalrog { 406*b45c03f5SMarkus Armbruster struct omap_lcd_panel_s *s = g_new0(struct omap_lcd_panel_s, 1); 407c3d2689dSbalrog 408c3d2689dSbalrog s->irq = irq; 409c3d2689dSbalrog s->dma = dma; 41075c9d6c2SAvi Kivity s->sysmem = sysmem; 411c3d2689dSbalrog omap_lcdc_reset(s); 412c3d2689dSbalrog 4132c9b15caSPaolo Bonzini memory_region_init_io(&s->iomem, NULL, &omap_lcdc_ops, s, "omap.lcdc", 0x100); 41430af1ec7SBenoît Canet memory_region_add_subregion(sysmem, base, &s->iomem); 415c3d2689dSbalrog 4165643706aSGerd Hoffmann s->con = graphic_console_init(NULL, 0, &omap_ops, s); 417c3d2689dSbalrog 418c3d2689dSbalrog return s; 419c3d2689dSbalrog } 420