exynos4210_fimd.c 68 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091929394959697989910010110210310410510610710810911011111211311411511611711811912012112212312412512612712812913013113213313413513613713813914014114214314414514614714814915015115215315415515615715815916016116216316416516616716816917017117217317417517617717817918018118218318418518618718818919019119219319419519619719819920020120220320420520620720820921021121221321421521621721821922022122222322422522622722822923023123223323423523623723823924024124224324424524624724824925025125225325425525625725825926026126226326426526626726826927027127227327427527627727827928028128228328428528628728828929029129229329429529629729829930030130230330430530630730830931031131231331431531631731831932032132232332432532632732832933033133233333433533633733833934034134234334434534634734834935035135235335435535635735835936036136236336436536636736836937037137237337437537637737837938038138238338438538638738838939039139239339439539639739839940040140240340440540640740840941041141241341441541641741841942042142242342442542642742842943043143243343443543643743843944044144244344444544644744844945045145245345445545645745845946046146246346446546646746846947047147247347447547647747847948048148248348448548648748848949049149249349449549649749849950050150250350450550650750850951051151251351451551651751851952052152252352452552652752852953053153253353453553653753853954054154254354454554654754854955055155255355455555655755855956056156256356456556656756856957057157257357457557657757857958058158258358458558658758858959059159259359459559659759859960060160260360460560660760860961061161261361461561661761861962062162262362462562662762862963063163263363463563663763863964064164264364464564664764864965065165265365465565665765865966066166266366466566666766866967067167267367467567667767867968068168268368468568668768868969069169269369469569669769869970070170270370470570670770870971071171271371471571671771871972072172272372472572672772872973073173273373473573673773873974074174274374474574674774874975075175275375475575675775875976076176276376476576676776876977077177277377477577677777877978078178278378478578678778878979079179279379479579679779879980080180280380480580680780880981081181281381481581681781881982082182282382482582682782882983083183283383483583683783883984084184284384484584684784884985085185285385485585685785885986086186286386486586686786886987087187287387487587687787887988088188288388488588688788888989089189289389489589689789889990090190290390490590690790890991091191291391491591691791891992092192292392492592692792892993093193293393493593693793893994094194294394494594694794894995095195295395495595695795895996096196296396496596696796896997097197297397497597697797897998098198298398498598698798898999099199299399499599699799899910001001100210031004100510061007100810091010101110121013101410151016101710181019102010211022102310241025102610271028102910301031103210331034103510361037103810391040104110421043104410451046104710481049105010511052105310541055105610571058105910601061106210631064106510661067106810691070107110721073107410751076107710781079108010811082108310841085108610871088108910901091109210931094109510961097109810991100110111021103110411051106110711081109111011111112111311141115111611171118111911201121112211231124112511261127112811291130113111321133113411351136113711381139114011411142114311441145114611471148114911501151115211531154115511561157115811591160116111621163116411651166116711681169117011711172117311741175117611771178117911801181118211831184118511861187118811891190119111921193119411951196119711981199120012011202120312041205120612071208120912101211121212131214121512161217121812191220122112221223122412251226122712281229123012311232123312341235123612371238123912401241124212431244124512461247124812491250125112521253125412551256125712581259126012611262126312641265126612671268126912701271127212731274127512761277127812791280128112821283128412851286128712881289129012911292129312941295129612971298129913001301130213031304130513061307130813091310131113121313131413151316131713181319132013211322132313241325132613271328132913301331133213331334133513361337133813391340134113421343134413451346134713481349135013511352135313541355135613571358135913601361136213631364136513661367136813691370137113721373137413751376137713781379138013811382138313841385138613871388138913901391139213931394139513961397139813991400140114021403140414051406140714081409141014111412141314141415141614171418141914201421142214231424142514261427142814291430143114321433143414351436143714381439144014411442144314441445144614471448144914501451145214531454145514561457145814591460146114621463146414651466146714681469147014711472147314741475147614771478147914801481148214831484148514861487148814891490149114921493149414951496149714981499150015011502150315041505150615071508150915101511151215131514151515161517151815191520152115221523152415251526152715281529153015311532153315341535153615371538153915401541154215431544154515461547154815491550155115521553155415551556155715581559156015611562156315641565156615671568156915701571157215731574157515761577157815791580158115821583158415851586158715881589159015911592159315941595159615971598159916001601160216031604160516061607160816091610161116121613161416151616161716181619162016211622162316241625162616271628162916301631163216331634163516361637163816391640164116421643164416451646164716481649165016511652165316541655165616571658165916601661166216631664166516661667166816691670167116721673167416751676167716781679168016811682168316841685168616871688168916901691169216931694169516961697169816991700170117021703170417051706170717081709171017111712171317141715171617171718171917201721172217231724172517261727172817291730173117321733173417351736173717381739174017411742174317441745174617471748174917501751175217531754175517561757175817591760176117621763176417651766176717681769177017711772177317741775177617771778177917801781178217831784178517861787178817891790179117921793179417951796179717981799180018011802180318041805180618071808180918101811181218131814181518161817181818191820182118221823182418251826182718281829183018311832183318341835183618371838183918401841184218431844184518461847184818491850185118521853185418551856185718581859186018611862186318641865186618671868186918701871187218731874187518761877187818791880188118821883188418851886188718881889189018911892189318941895189618971898189919001901190219031904190519061907190819091910191119121913191419151916191719181919192019211922192319241925192619271928192919301931193219331934193519361937193819391940194119421943194419451946194719481949195019511952195319541955195619571958
  1. /*
  2. * Samsung exynos4210 Display Controller (FIMD)
  3. *
  4. * Copyright (c) 2000 - 2011 Samsung Electronics Co., Ltd.
  5. * All rights reserved.
  6. * Based on LCD controller for Samsung S5PC1xx-based board emulation
  7. * by Kirill Batuzov <batuzovk@ispras.ru>
  8. *
  9. * Contributed by Mitsyanko Igor <i.mitsyanko@samsung.com>
  10. *
  11. * This program is free software; you can redistribute it and/or modify it
  12. * under the terms of the GNU General Public License as published by the
  13. * Free Software Foundation; either version 2 of the License, or (at your
  14. * option) any later version.
  15. *
  16. * This program is distributed in the hope that it will be useful,
  17. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  18. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  19. * See the GNU General Public License for more details.
  20. *
  21. * You should have received a copy of the GNU General Public License along
  22. * with this program; if not, see <http://www.gnu.org/licenses/>.
  23. */
  24. #include "qemu/osdep.h"
  25. #include "hw/hw.h"
  26. #include "hw/irq.h"
  27. #include "hw/sysbus.h"
  28. #include "migration/vmstate.h"
  29. #include "ui/console.h"
  30. #include "ui/pixel_ops.h"
  31. #include "qemu/bswap.h"
  32. #include "qemu/module.h"
  33. /* Debug messages configuration */
  34. #define EXYNOS4210_FIMD_DEBUG 0
  35. #define EXYNOS4210_FIMD_MODE_TRACE 0
  36. #if EXYNOS4210_FIMD_DEBUG == 0
  37. #define DPRINT_L1(fmt, args...) do { } while (0)
  38. #define DPRINT_L2(fmt, args...) do { } while (0)
  39. #define DPRINT_ERROR(fmt, args...) do { } while (0)
  40. #elif EXYNOS4210_FIMD_DEBUG == 1
  41. #define DPRINT_L1(fmt, args...) \
  42. do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
  43. #define DPRINT_L2(fmt, args...) do { } while (0)
  44. #define DPRINT_ERROR(fmt, args...) \
  45. do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
  46. #else
  47. #define DPRINT_L1(fmt, args...) \
  48. do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
  49. #define DPRINT_L2(fmt, args...) \
  50. do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
  51. #define DPRINT_ERROR(fmt, args...) \
  52. do {fprintf(stderr, "QEMU FIMD ERROR: "fmt, ## args); } while (0)
  53. #endif
  54. #if EXYNOS4210_FIMD_MODE_TRACE == 0
  55. #define DPRINT_TRACE(fmt, args...) do { } while (0)
  56. #else
  57. #define DPRINT_TRACE(fmt, args...) \
  58. do {fprintf(stderr, "QEMU FIMD: "fmt, ## args); } while (0)
  59. #endif
  60. #define NUM_OF_WINDOWS 5
  61. #define FIMD_REGS_SIZE 0x4114
  62. /* Video main control registers */
  63. #define FIMD_VIDCON0 0x0000
  64. #define FIMD_VIDCON1 0x0004
  65. #define FIMD_VIDCON2 0x0008
  66. #define FIMD_VIDCON3 0x000C
  67. #define FIMD_VIDCON0_ENVID_F (1 << 0)
  68. #define FIMD_VIDCON0_ENVID (1 << 1)
  69. #define FIMD_VIDCON0_ENVID_MASK ((1 << 0) | (1 << 1))
  70. #define FIMD_VIDCON1_ROMASK 0x07FFE000
  71. /* Video time control registers */
  72. #define FIMD_VIDTCON_START 0x10
  73. #define FIMD_VIDTCON_END 0x1C
  74. #define FIMD_VIDTCON2_SIZE_MASK 0x07FF
  75. #define FIMD_VIDTCON2_HOR_SHIFT 0
  76. #define FIMD_VIDTCON2_VER_SHIFT 11
  77. /* Window control registers */
  78. #define FIMD_WINCON_START 0x0020
  79. #define FIMD_WINCON_END 0x0030
  80. #define FIMD_WINCON_ROMASK 0x82200000
  81. #define FIMD_WINCON_ENWIN (1 << 0)
  82. #define FIMD_WINCON_BLD_PIX (1 << 6)
  83. #define FIMD_WINCON_ALPHA_MUL (1 << 7)
  84. #define FIMD_WINCON_ALPHA_SEL (1 << 1)
  85. #define FIMD_WINCON_SWAP 0x078000
  86. #define FIMD_WINCON_SWAP_SHIFT 15
  87. #define FIMD_WINCON_SWAP_WORD 0x1
  88. #define FIMD_WINCON_SWAP_HWORD 0x2
  89. #define FIMD_WINCON_SWAP_BYTE 0x4
  90. #define FIMD_WINCON_SWAP_BITS 0x8
  91. #define FIMD_WINCON_BUFSTAT_L (1 << 21)
  92. #define FIMD_WINCON_BUFSTAT_H (1 << 31)
  93. #define FIMD_WINCON_BUFSTATUS ((1 << 21) | (1 << 31))
  94. #define FIMD_WINCON_BUF0_STAT ((0 << 21) | (0 << 31))
  95. #define FIMD_WINCON_BUF1_STAT ((1 << 21) | (0 << 31))
  96. #define FIMD_WINCON_BUF2_STAT ((0 << 21) | (1U << 31))
  97. #define FIMD_WINCON_BUFSELECT ((1 << 20) | (1 << 30))
  98. #define FIMD_WINCON_BUF0_SEL ((0 << 20) | (0 << 30))
  99. #define FIMD_WINCON_BUF1_SEL ((1 << 20) | (0 << 30))
  100. #define FIMD_WINCON_BUF2_SEL ((0 << 20) | (1 << 30))
  101. #define FIMD_WINCON_BUFMODE (1 << 14)
  102. #define IS_PALETTIZED_MODE(w) (w->wincon & 0xC)
  103. #define PAL_MODE_WITH_ALPHA(x) ((x) == 7)
  104. #define WIN_BPP_MODE(w) ((w->wincon >> 2) & 0xF)
  105. #define WIN_BPP_MODE_WITH_ALPHA(w) \
  106. (WIN_BPP_MODE(w) == 0xD || WIN_BPP_MODE(w) == 0xE)
  107. /* Shadow control register */
  108. #define FIMD_SHADOWCON 0x0034
  109. #define FIMD_WINDOW_PROTECTED(s, w) ((s) & (1 << (10 + (w))))
  110. /* Channel mapping control register */
  111. #define FIMD_WINCHMAP 0x003C
  112. /* Window position control registers */
  113. #define FIMD_VIDOSD_START 0x0040
  114. #define FIMD_VIDOSD_END 0x0088
  115. #define FIMD_VIDOSD_COORD_MASK 0x07FF
  116. #define FIMD_VIDOSD_HOR_SHIFT 11
  117. #define FIMD_VIDOSD_VER_SHIFT 0
  118. #define FIMD_VIDOSD_ALPHA_AEN0 0xFFF000
  119. #define FIMD_VIDOSD_AEN0_SHIFT 12
  120. #define FIMD_VIDOSD_ALPHA_AEN1 0x000FFF
  121. /* Frame buffer address registers */
  122. #define FIMD_VIDWADD0_START 0x00A0
  123. #define FIMD_VIDWADD0_END 0x00C4
  124. #define FIMD_VIDWADD0_END 0x00C4
  125. #define FIMD_VIDWADD1_START 0x00D0
  126. #define FIMD_VIDWADD1_END 0x00F4
  127. #define FIMD_VIDWADD2_START 0x0100
  128. #define FIMD_VIDWADD2_END 0x0110
  129. #define FIMD_VIDWADD2_PAGEWIDTH 0x1FFF
  130. #define FIMD_VIDWADD2_OFFSIZE 0x1FFF
  131. #define FIMD_VIDWADD2_OFFSIZE_SHIFT 13
  132. #define FIMD_VIDW0ADD0_B2 0x20A0
  133. #define FIMD_VIDW4ADD0_B2 0x20C0
  134. /* Video interrupt control registers */
  135. #define FIMD_VIDINTCON0 0x130
  136. #define FIMD_VIDINTCON1 0x134
  137. /* Window color key registers */
  138. #define FIMD_WKEYCON_START 0x140
  139. #define FIMD_WKEYCON_END 0x15C
  140. #define FIMD_WKEYCON0_COMPKEY 0x00FFFFFF
  141. #define FIMD_WKEYCON0_CTL_SHIFT 24
  142. #define FIMD_WKEYCON0_DIRCON (1 << 24)
  143. #define FIMD_WKEYCON0_KEYEN (1 << 25)
  144. #define FIMD_WKEYCON0_KEYBLEN (1 << 26)
  145. /* Window color key alpha control register */
  146. #define FIMD_WKEYALPHA_START 0x160
  147. #define FIMD_WKEYALPHA_END 0x16C
  148. /* Dithering control register */
  149. #define FIMD_DITHMODE 0x170
  150. /* Window alpha control registers */
  151. #define FIMD_VIDALPHA_ALPHA_LOWER 0x000F0F0F
  152. #define FIMD_VIDALPHA_ALPHA_UPPER 0x00F0F0F0
  153. #define FIMD_VIDWALPHA_START 0x21C
  154. #define FIMD_VIDWALPHA_END 0x240
  155. /* Window color map registers */
  156. #define FIMD_WINMAP_START 0x180
  157. #define FIMD_WINMAP_END 0x190
  158. #define FIMD_WINMAP_EN (1 << 24)
  159. #define FIMD_WINMAP_COLOR_MASK 0x00FFFFFF
  160. /* Window palette control registers */
  161. #define FIMD_WPALCON_HIGH 0x019C
  162. #define FIMD_WPALCON_LOW 0x01A0
  163. #define FIMD_WPALCON_UPDATEEN (1 << 9)
  164. #define FIMD_WPAL_W0PAL_L 0x07
  165. #define FIMD_WPAL_W0PAL_L_SHT 0
  166. #define FIMD_WPAL_W1PAL_L 0x07
  167. #define FIMD_WPAL_W1PAL_L_SHT 3
  168. #define FIMD_WPAL_W2PAL_L 0x01
  169. #define FIMD_WPAL_W2PAL_L_SHT 6
  170. #define FIMD_WPAL_W2PAL_H 0x06
  171. #define FIMD_WPAL_W2PAL_H_SHT 8
  172. #define FIMD_WPAL_W3PAL_L 0x01
  173. #define FIMD_WPAL_W3PAL_L_SHT 7
  174. #define FIMD_WPAL_W3PAL_H 0x06
  175. #define FIMD_WPAL_W3PAL_H_SHT 12
  176. #define FIMD_WPAL_W4PAL_L 0x01
  177. #define FIMD_WPAL_W4PAL_L_SHT 8
  178. #define FIMD_WPAL_W4PAL_H 0x06
  179. #define FIMD_WPAL_W4PAL_H_SHT 16
  180. /* Trigger control registers */
  181. #define FIMD_TRIGCON 0x01A4
  182. #define FIMD_TRIGCON_ROMASK 0x00000004
  183. /* LCD I80 Interface Control */
  184. #define FIMD_I80IFCON_START 0x01B0
  185. #define FIMD_I80IFCON_END 0x01BC
  186. /* Color gain control register */
  187. #define FIMD_COLORGAINCON 0x01C0
  188. /* LCD i80 Interface Command Control */
  189. #define FIMD_LDI_CMDCON0 0x01D0
  190. #define FIMD_LDI_CMDCON1 0x01D4
  191. /* I80 System Interface Manual Command Control */
  192. #define FIMD_SIFCCON0 0x01E0
  193. #define FIMD_SIFCCON2 0x01E8
  194. /* Hue Control Registers */
  195. #define FIMD_HUECOEFCR_START 0x01EC
  196. #define FIMD_HUECOEFCR_END 0x01F4
  197. #define FIMD_HUECOEFCB_START 0x01FC
  198. #define FIMD_HUECOEFCB_END 0x0208
  199. #define FIMD_HUEOFFSET 0x020C
  200. /* Video interrupt control registers */
  201. #define FIMD_VIDINT_INTFIFOPEND (1 << 0)
  202. #define FIMD_VIDINT_INTFRMPEND (1 << 1)
  203. #define FIMD_VIDINT_INTI80PEND (1 << 2)
  204. #define FIMD_VIDINT_INTEN (1 << 0)
  205. #define FIMD_VIDINT_INTFIFOEN (1 << 1)
  206. #define FIMD_VIDINT_INTFRMEN (1 << 12)
  207. #define FIMD_VIDINT_I80IFDONE (1 << 17)
  208. /* Window blend equation control registers */
  209. #define FIMD_BLENDEQ_START 0x0244
  210. #define FIMD_BLENDEQ_END 0x0250
  211. #define FIMD_BLENDCON 0x0260
  212. #define FIMD_ALPHA_8BIT (1 << 0)
  213. #define FIMD_BLENDEQ_COEF_MASK 0xF
  214. /* Window RTQOS Control Registers */
  215. #define FIMD_WRTQOSCON_START 0x0264
  216. #define FIMD_WRTQOSCON_END 0x0274
  217. /* LCD I80 Interface Command */
  218. #define FIMD_I80IFCMD_START 0x0280
  219. #define FIMD_I80IFCMD_END 0x02AC
  220. /* Shadow windows control registers */
  221. #define FIMD_SHD_ADD0_START 0x40A0
  222. #define FIMD_SHD_ADD0_END 0x40C0
  223. #define FIMD_SHD_ADD1_START 0x40D0
  224. #define FIMD_SHD_ADD1_END 0x40F0
  225. #define FIMD_SHD_ADD2_START 0x4100
  226. #define FIMD_SHD_ADD2_END 0x4110
  227. /* Palette memory */
  228. #define FIMD_PAL_MEM_START 0x2400
  229. #define FIMD_PAL_MEM_END 0x37FC
  230. /* Palette memory aliases for windows 0 and 1 */
  231. #define FIMD_PALMEM_AL_START 0x0400
  232. #define FIMD_PALMEM_AL_END 0x0BFC
  233. typedef struct {
  234. uint8_t r, g, b;
  235. /* D[31..24]dummy, D[23..16]rAlpha, D[15..8]gAlpha, D[7..0]bAlpha */
  236. uint32_t a;
  237. } rgba;
  238. #define RGBA_SIZE 7
  239. typedef void pixel_to_rgb_func(uint32_t pixel, rgba *p);
  240. typedef struct Exynos4210fimdWindow Exynos4210fimdWindow;
  241. struct Exynos4210fimdWindow {
  242. uint32_t wincon; /* Window control register */
  243. uint32_t buf_start[3]; /* Start address for video frame buffer */
  244. uint32_t buf_end[3]; /* End address for video frame buffer */
  245. uint32_t keycon[2]; /* Window color key registers */
  246. uint32_t keyalpha; /* Color key alpha control register */
  247. uint32_t winmap; /* Window color map register */
  248. uint32_t blendeq; /* Window blending equation control register */
  249. uint32_t rtqoscon; /* Window RTQOS Control Registers */
  250. uint32_t palette[256]; /* Palette RAM */
  251. uint32_t shadow_buf_start; /* Start address of shadow frame buffer */
  252. uint32_t shadow_buf_end; /* End address of shadow frame buffer */
  253. uint32_t shadow_buf_size; /* Virtual shadow screen width */
  254. pixel_to_rgb_func *pixel_to_rgb;
  255. void (*draw_line)(Exynos4210fimdWindow *w, uint8_t *src, uint8_t *dst,
  256. bool blend);
  257. uint32_t (*get_alpha)(Exynos4210fimdWindow *w, uint32_t pix_a);
  258. uint16_t lefttop_x, lefttop_y; /* VIDOSD0 register */
  259. uint16_t rightbot_x, rightbot_y; /* VIDOSD1 register */
  260. uint32_t osdsize; /* VIDOSD2&3 register */
  261. uint32_t alpha_val[2]; /* VIDOSD2&3, VIDWALPHA registers */
  262. uint16_t virtpage_width; /* VIDWADD2 register */
  263. uint16_t virtpage_offsize; /* VIDWADD2 register */
  264. MemoryRegionSection mem_section; /* RAM fragment containing framebuffer */
  265. uint8_t *host_fb_addr; /* Host pointer to window's framebuffer */
  266. hwaddr fb_len; /* Framebuffer length */
  267. };
  268. #define TYPE_EXYNOS4210_FIMD "exynos4210.fimd"
  269. #define EXYNOS4210_FIMD(obj) \
  270. OBJECT_CHECK(Exynos4210fimdState, (obj), TYPE_EXYNOS4210_FIMD)
  271. typedef struct {
  272. SysBusDevice parent_obj;
  273. MemoryRegion iomem;
  274. QemuConsole *console;
  275. qemu_irq irq[3];
  276. uint32_t vidcon[4]; /* Video main control registers 0-3 */
  277. uint32_t vidtcon[4]; /* Video time control registers 0-3 */
  278. uint32_t shadowcon; /* Window shadow control register */
  279. uint32_t winchmap; /* Channel mapping control register */
  280. uint32_t vidintcon[2]; /* Video interrupt control registers */
  281. uint32_t dithmode; /* Dithering control register */
  282. uint32_t wpalcon[2]; /* Window palette control registers */
  283. uint32_t trigcon; /* Trigger control register */
  284. uint32_t i80ifcon[4]; /* I80 interface control registers */
  285. uint32_t colorgaincon; /* Color gain control register */
  286. uint32_t ldi_cmdcon[2]; /* LCD I80 interface command control */
  287. uint32_t sifccon[3]; /* I80 System Interface Manual Command Control */
  288. uint32_t huecoef_cr[4]; /* Hue control registers */
  289. uint32_t huecoef_cb[4]; /* Hue control registers */
  290. uint32_t hueoffset; /* Hue offset control register */
  291. uint32_t blendcon; /* Blending control register */
  292. uint32_t i80ifcmd[12]; /* LCD I80 Interface Command */
  293. Exynos4210fimdWindow window[5]; /* Window-specific registers */
  294. uint8_t *ifb; /* Internal frame buffer */
  295. bool invalidate; /* Image needs to be redrawn */
  296. bool enabled; /* Display controller is enabled */
  297. } Exynos4210fimdState;
  298. /* Perform byte/halfword/word swap of data according to WINCON */
  299. static inline void fimd_swap_data(unsigned int swap_ctl, uint64_t *data)
  300. {
  301. int i;
  302. uint64_t res;
  303. uint64_t x = *data;
  304. if (swap_ctl & FIMD_WINCON_SWAP_BITS) {
  305. res = 0;
  306. for (i = 0; i < 64; i++) {
  307. if (x & (1ULL << (63 - i))) {
  308. res |= (1ULL << i);
  309. }
  310. }
  311. x = res;
  312. }
  313. if (swap_ctl & FIMD_WINCON_SWAP_BYTE) {
  314. x = bswap64(x);
  315. }
  316. if (swap_ctl & FIMD_WINCON_SWAP_HWORD) {
  317. x = ((x & 0x000000000000FFFFULL) << 48) |
  318. ((x & 0x00000000FFFF0000ULL) << 16) |
  319. ((x & 0x0000FFFF00000000ULL) >> 16) |
  320. ((x & 0xFFFF000000000000ULL) >> 48);
  321. }
  322. if (swap_ctl & FIMD_WINCON_SWAP_WORD) {
  323. x = ((x & 0x00000000FFFFFFFFULL) << 32) |
  324. ((x & 0xFFFFFFFF00000000ULL) >> 32);
  325. }
  326. *data = x;
  327. }
  328. /* Conversion routines of Pixel data from frame buffer area to internal RGBA
  329. * pixel representation.
  330. * Every color component internally represented as 8-bit value. If original
  331. * data has less than 8 bit for component, data is extended to 8 bit. For
  332. * example, if blue component has only two possible values 0 and 1 it will be
  333. * extended to 0 and 0xFF */
  334. /* One bit for alpha representation */
  335. #define DEF_PIXEL_TO_RGB_A1(N, R, G, B) \
  336. static void N(uint32_t pixel, rgba *p) \
  337. { \
  338. p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
  339. ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
  340. pixel >>= (B); \
  341. p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
  342. ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
  343. pixel >>= (G); \
  344. p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
  345. ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
  346. pixel >>= (R); \
  347. p->a = (pixel & 0x1); \
  348. }
  349. DEF_PIXEL_TO_RGB_A1(pixel_a444_to_rgb, 4, 4, 4)
  350. DEF_PIXEL_TO_RGB_A1(pixel_a555_to_rgb, 5, 5, 5)
  351. DEF_PIXEL_TO_RGB_A1(pixel_a666_to_rgb, 6, 6, 6)
  352. DEF_PIXEL_TO_RGB_A1(pixel_a665_to_rgb, 6, 6, 5)
  353. DEF_PIXEL_TO_RGB_A1(pixel_a888_to_rgb, 8, 8, 8)
  354. DEF_PIXEL_TO_RGB_A1(pixel_a887_to_rgb, 8, 8, 7)
  355. /* Alpha component is always zero */
  356. #define DEF_PIXEL_TO_RGB_A0(N, R, G, B) \
  357. static void N(uint32_t pixel, rgba *p) \
  358. { \
  359. p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
  360. ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
  361. pixel >>= (B); \
  362. p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
  363. ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
  364. pixel >>= (G); \
  365. p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
  366. ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
  367. p->a = 0x0; \
  368. }
  369. DEF_PIXEL_TO_RGB_A0(pixel_565_to_rgb, 5, 6, 5)
  370. DEF_PIXEL_TO_RGB_A0(pixel_555_to_rgb, 5, 5, 5)
  371. DEF_PIXEL_TO_RGB_A0(pixel_666_to_rgb, 6, 6, 6)
  372. DEF_PIXEL_TO_RGB_A0(pixel_888_to_rgb, 8, 8, 8)
  373. /* Alpha component has some meaningful value */
  374. #define DEF_PIXEL_TO_RGB_A(N, R, G, B, A) \
  375. static void N(uint32_t pixel, rgba *p) \
  376. { \
  377. p->b = ((pixel & ((1 << (B)) - 1)) << (8 - (B))) | \
  378. ((pixel >> (2 * (B) - 8)) & ((1 << (8 - (B))) - 1)); \
  379. pixel >>= (B); \
  380. p->g = (pixel & ((1 << (G)) - 1)) << (8 - (G)) | \
  381. ((pixel >> (2 * (G) - 8)) & ((1 << (8 - (G))) - 1)); \
  382. pixel >>= (G); \
  383. p->r = (pixel & ((1 << (R)) - 1)) << (8 - (R)) | \
  384. ((pixel >> (2 * (R) - 8)) & ((1 << (8 - (R))) - 1)); \
  385. pixel >>= (R); \
  386. p->a = (pixel & ((1 << (A)) - 1)) << (8 - (A)) | \
  387. ((pixel >> (2 * (A) - 8)) & ((1 << (8 - (A))) - 1)); \
  388. p->a = p->a | (p->a << 8) | (p->a << 16); \
  389. }
  390. DEF_PIXEL_TO_RGB_A(pixel_4444_to_rgb, 4, 4, 4, 4)
  391. DEF_PIXEL_TO_RGB_A(pixel_8888_to_rgb, 8, 8, 8, 8)
  392. /* Lookup table to extent 2-bit color component to 8 bit */
  393. static const uint8_t pixel_lutable_2b[4] = {
  394. 0x0, 0x55, 0xAA, 0xFF
  395. };
  396. /* Lookup table to extent 3-bit color component to 8 bit */
  397. static const uint8_t pixel_lutable_3b[8] = {
  398. 0x0, 0x24, 0x49, 0x6D, 0x92, 0xB6, 0xDB, 0xFF
  399. };
  400. /* Special case for a232 bpp mode */
  401. static void pixel_a232_to_rgb(uint32_t pixel, rgba *p)
  402. {
  403. p->b = pixel_lutable_2b[(pixel & 0x3)];
  404. pixel >>= 2;
  405. p->g = pixel_lutable_3b[(pixel & 0x7)];
  406. pixel >>= 3;
  407. p->r = pixel_lutable_2b[(pixel & 0x3)];
  408. pixel >>= 2;
  409. p->a = (pixel & 0x1);
  410. }
  411. /* Special case for (5+1, 5+1, 5+1) mode. Data bit 15 is common LSB
  412. * for all three color components */
  413. static void pixel_1555_to_rgb(uint32_t pixel, rgba *p)
  414. {
  415. uint8_t comm = (pixel >> 15) & 1;
  416. p->b = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
  417. pixel >>= 5;
  418. p->g = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
  419. pixel >>= 5;
  420. p->r = ((((pixel & 0x1F) << 1) | comm) << 2) | ((pixel >> 3) & 0x3);
  421. p->a = 0x0;
  422. }
  423. /* Put/get pixel to/from internal LCD Controller framebuffer */
  424. static int put_pixel_ifb(const rgba p, uint8_t *d)
  425. {
  426. *(uint8_t *)d++ = p.r;
  427. *(uint8_t *)d++ = p.g;
  428. *(uint8_t *)d++ = p.b;
  429. *(uint32_t *)d = p.a;
  430. return RGBA_SIZE;
  431. }
  432. static int get_pixel_ifb(const uint8_t *s, rgba *p)
  433. {
  434. p->r = *(uint8_t *)s++;
  435. p->g = *(uint8_t *)s++;
  436. p->b = *(uint8_t *)s++;
  437. p->a = (*(uint32_t *)s) & 0x00FFFFFF;
  438. return RGBA_SIZE;
  439. }
  440. static pixel_to_rgb_func *palette_data_format[8] = {
  441. [0] = pixel_565_to_rgb,
  442. [1] = pixel_a555_to_rgb,
  443. [2] = pixel_666_to_rgb,
  444. [3] = pixel_a665_to_rgb,
  445. [4] = pixel_a666_to_rgb,
  446. [5] = pixel_888_to_rgb,
  447. [6] = pixel_a888_to_rgb,
  448. [7] = pixel_8888_to_rgb
  449. };
  450. /* Returns Index in palette data formats table for given window number WINDOW */
  451. static uint32_t
  452. exynos4210_fimd_palette_format(Exynos4210fimdState *s, int window)
  453. {
  454. uint32_t ret;
  455. switch (window) {
  456. case 0:
  457. ret = (s->wpalcon[1] >> FIMD_WPAL_W0PAL_L_SHT) & FIMD_WPAL_W0PAL_L;
  458. if (ret != 7) {
  459. ret = 6 - ret;
  460. }
  461. break;
  462. case 1:
  463. ret = (s->wpalcon[1] >> FIMD_WPAL_W1PAL_L_SHT) & FIMD_WPAL_W1PAL_L;
  464. if (ret != 7) {
  465. ret = 6 - ret;
  466. }
  467. break;
  468. case 2:
  469. ret = ((s->wpalcon[0] >> FIMD_WPAL_W2PAL_H_SHT) & FIMD_WPAL_W2PAL_H) |
  470. ((s->wpalcon[1] >> FIMD_WPAL_W2PAL_L_SHT) & FIMD_WPAL_W2PAL_L);
  471. break;
  472. case 3:
  473. ret = ((s->wpalcon[0] >> FIMD_WPAL_W3PAL_H_SHT) & FIMD_WPAL_W3PAL_H) |
  474. ((s->wpalcon[1] >> FIMD_WPAL_W3PAL_L_SHT) & FIMD_WPAL_W3PAL_L);
  475. break;
  476. case 4:
  477. ret = ((s->wpalcon[0] >> FIMD_WPAL_W4PAL_H_SHT) & FIMD_WPAL_W4PAL_H) |
  478. ((s->wpalcon[1] >> FIMD_WPAL_W4PAL_L_SHT) & FIMD_WPAL_W4PAL_L);
  479. break;
  480. default:
  481. hw_error("exynos4210.fimd: incorrect window number %d\n", window);
  482. ret = 0;
  483. break;
  484. }
  485. return ret;
  486. }
  487. #define FIMD_1_MINUS_COLOR(x) \
  488. ((0xFF - ((x) & 0xFF)) | (0xFF00 - ((x) & 0xFF00)) | \
  489. (0xFF0000 - ((x) & 0xFF0000)))
  490. #define EXTEND_LOWER_HALFBYTE(x) (((x) & 0xF0F0F) | (((x) << 4) & 0xF0F0F0))
  491. #define EXTEND_UPPER_HALFBYTE(x) (((x) & 0xF0F0F0) | (((x) >> 4) & 0xF0F0F))
  492. /* Multiply three lower bytes of two 32-bit words with each other.
  493. * Each byte with values 0-255 is considered as a number with possible values
  494. * in a range [0 - 1] */
  495. static inline uint32_t fimd_mult_each_byte(uint32_t a, uint32_t b)
  496. {
  497. uint32_t tmp;
  498. uint32_t ret;
  499. ret = ((tmp = (((a & 0xFF) * (b & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF : tmp;
  500. ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF)) / 0xFF)) > 0xFF) ?
  501. 0xFF00 : tmp << 8;
  502. ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
  503. 0xFF0000 : tmp << 16;
  504. return ret;
  505. }
  506. /* For each corresponding bytes of two 32-bit words: (a*b + c*d)
  507. * Byte values 0-255 are mapped to a range [0 .. 1] */
  508. static inline uint32_t
  509. fimd_mult_and_sum_each_byte(uint32_t a, uint32_t b, uint32_t c, uint32_t d)
  510. {
  511. uint32_t tmp;
  512. uint32_t ret;
  513. ret = ((tmp = (((a & 0xFF) * (b & 0xFF) + (c & 0xFF) * (d & 0xFF)) / 0xFF))
  514. > 0xFF) ? 0xFF : tmp;
  515. ret |= ((tmp = ((((a >> 8) & 0xFF) * ((b >> 8) & 0xFF) + ((c >> 8) & 0xFF) *
  516. ((d >> 8) & 0xFF)) / 0xFF)) > 0xFF) ? 0xFF00 : tmp << 8;
  517. ret |= ((tmp = ((((a >> 16) & 0xFF) * ((b >> 16) & 0xFF) +
  518. ((c >> 16) & 0xFF) * ((d >> 16) & 0xFF)) / 0xFF)) > 0xFF) ?
  519. 0xFF0000 : tmp << 16;
  520. return ret;
  521. }
  522. /* These routines cover all possible sources of window's transparent factor
  523. * used in blending equation. Choice of routine is affected by WPALCON
  524. * registers, BLENDCON register and window's WINCON register */
  525. static uint32_t fimd_get_alpha_pix(Exynos4210fimdWindow *w, uint32_t pix_a)
  526. {
  527. return pix_a;
  528. }
  529. static uint32_t
  530. fimd_get_alpha_pix_extlow(Exynos4210fimdWindow *w, uint32_t pix_a)
  531. {
  532. return EXTEND_LOWER_HALFBYTE(pix_a);
  533. }
  534. static uint32_t
  535. fimd_get_alpha_pix_exthigh(Exynos4210fimdWindow *w, uint32_t pix_a)
  536. {
  537. return EXTEND_UPPER_HALFBYTE(pix_a);
  538. }
  539. static uint32_t fimd_get_alpha_mult(Exynos4210fimdWindow *w, uint32_t pix_a)
  540. {
  541. return fimd_mult_each_byte(pix_a, w->alpha_val[0]);
  542. }
  543. static uint32_t fimd_get_alpha_mult_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
  544. {
  545. return fimd_mult_each_byte(EXTEND_LOWER_HALFBYTE(pix_a),
  546. EXTEND_UPPER_HALFBYTE(w->alpha_val[0]));
  547. }
  548. static uint32_t fimd_get_alpha_aen(Exynos4210fimdWindow *w, uint32_t pix_a)
  549. {
  550. return w->alpha_val[pix_a];
  551. }
  552. static uint32_t fimd_get_alpha_aen_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
  553. {
  554. return EXTEND_UPPER_HALFBYTE(w->alpha_val[pix_a]);
  555. }
  556. static uint32_t fimd_get_alpha_sel(Exynos4210fimdWindow *w, uint32_t pix_a)
  557. {
  558. return w->alpha_val[(w->wincon & FIMD_WINCON_ALPHA_SEL) ? 1 : 0];
  559. }
  560. static uint32_t fimd_get_alpha_sel_ext(Exynos4210fimdWindow *w, uint32_t pix_a)
  561. {
  562. return EXTEND_UPPER_HALFBYTE(w->alpha_val[(w->wincon &
  563. FIMD_WINCON_ALPHA_SEL) ? 1 : 0]);
  564. }
  565. /* Updates currently active alpha value get function for specified window */
  566. static void fimd_update_get_alpha(Exynos4210fimdState *s, int win)
  567. {
  568. Exynos4210fimdWindow *w = &s->window[win];
  569. const bool alpha_is_8bit = s->blendcon & FIMD_ALPHA_8BIT;
  570. if (w->wincon & FIMD_WINCON_BLD_PIX) {
  571. if ((w->wincon & FIMD_WINCON_ALPHA_SEL) && WIN_BPP_MODE_WITH_ALPHA(w)) {
  572. /* In this case, alpha component contains meaningful value */
  573. if (w->wincon & FIMD_WINCON_ALPHA_MUL) {
  574. w->get_alpha = alpha_is_8bit ?
  575. fimd_get_alpha_mult : fimd_get_alpha_mult_ext;
  576. } else {
  577. w->get_alpha = alpha_is_8bit ?
  578. fimd_get_alpha_pix : fimd_get_alpha_pix_extlow;
  579. }
  580. } else {
  581. if (IS_PALETTIZED_MODE(w) &&
  582. PAL_MODE_WITH_ALPHA(exynos4210_fimd_palette_format(s, win))) {
  583. /* Alpha component has 8-bit numeric value */
  584. w->get_alpha = alpha_is_8bit ?
  585. fimd_get_alpha_pix : fimd_get_alpha_pix_exthigh;
  586. } else {
  587. /* Alpha has only two possible values (AEN) */
  588. w->get_alpha = alpha_is_8bit ?
  589. fimd_get_alpha_aen : fimd_get_alpha_aen_ext;
  590. }
  591. }
  592. } else {
  593. w->get_alpha = alpha_is_8bit ? fimd_get_alpha_sel :
  594. fimd_get_alpha_sel_ext;
  595. }
  596. }
  597. /* Blends current window's (w) pixel (foreground pixel *ret) with background
  598. * window (w_blend) pixel p_bg according to formula:
  599. * NEW_COLOR = a_coef x FG_PIXEL_COLOR + b_coef x BG_PIXEL_COLOR
  600. * NEW_ALPHA = p_coef x FG_ALPHA + q_coef x BG_ALPHA
  601. */
  602. static void
  603. exynos4210_fimd_blend_pixel(Exynos4210fimdWindow *w, rgba p_bg, rgba *ret)
  604. {
  605. rgba p_fg = *ret;
  606. uint32_t bg_color = ((p_bg.r & 0xFF) << 16) | ((p_bg.g & 0xFF) << 8) |
  607. (p_bg.b & 0xFF);
  608. uint32_t fg_color = ((p_fg.r & 0xFF) << 16) | ((p_fg.g & 0xFF) << 8) |
  609. (p_fg.b & 0xFF);
  610. uint32_t alpha_fg = p_fg.a;
  611. int i;
  612. /* It is possible that blending equation parameters a and b do not
  613. * depend on window BLENEQ register. Account for this with first_coef */
  614. enum { A_COEF = 0, B_COEF = 1, P_COEF = 2, Q_COEF = 3, COEF_NUM = 4};
  615. uint32_t first_coef = A_COEF;
  616. uint32_t blend_param[COEF_NUM];
  617. if (w->keycon[0] & FIMD_WKEYCON0_KEYEN) {
  618. uint32_t colorkey = (w->keycon[1] &
  619. ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) & FIMD_WKEYCON0_COMPKEY;
  620. if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) &&
  621. (bg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
  622. /* Foreground pixel is displayed */
  623. if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
  624. alpha_fg = w->keyalpha;
  625. blend_param[A_COEF] = alpha_fg;
  626. blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
  627. } else {
  628. alpha_fg = 0;
  629. blend_param[A_COEF] = 0xFFFFFF;
  630. blend_param[B_COEF] = 0x0;
  631. }
  632. first_coef = P_COEF;
  633. } else if ((w->keycon[0] & FIMD_WKEYCON0_DIRCON) == 0 &&
  634. (fg_color & ~(w->keycon[0] & FIMD_WKEYCON0_COMPKEY)) == colorkey) {
  635. /* Background pixel is displayed */
  636. if (w->keycon[0] & FIMD_WKEYCON0_KEYBLEN) {
  637. alpha_fg = w->keyalpha;
  638. blend_param[A_COEF] = alpha_fg;
  639. blend_param[B_COEF] = FIMD_1_MINUS_COLOR(alpha_fg);
  640. } else {
  641. alpha_fg = 0;
  642. blend_param[A_COEF] = 0x0;
  643. blend_param[B_COEF] = 0xFFFFFF;
  644. }
  645. first_coef = P_COEF;
  646. }
  647. }
  648. for (i = first_coef; i < COEF_NUM; i++) {
  649. switch ((w->blendeq >> i * 6) & FIMD_BLENDEQ_COEF_MASK) {
  650. case 0:
  651. blend_param[i] = 0;
  652. break;
  653. case 1:
  654. blend_param[i] = 0xFFFFFF;
  655. break;
  656. case 2:
  657. blend_param[i] = alpha_fg;
  658. break;
  659. case 3:
  660. blend_param[i] = FIMD_1_MINUS_COLOR(alpha_fg);
  661. break;
  662. case 4:
  663. blend_param[i] = p_bg.a;
  664. break;
  665. case 5:
  666. blend_param[i] = FIMD_1_MINUS_COLOR(p_bg.a);
  667. break;
  668. case 6:
  669. blend_param[i] = w->alpha_val[0];
  670. break;
  671. case 10:
  672. blend_param[i] = fg_color;
  673. break;
  674. case 11:
  675. blend_param[i] = FIMD_1_MINUS_COLOR(fg_color);
  676. break;
  677. case 12:
  678. blend_param[i] = bg_color;
  679. break;
  680. case 13:
  681. blend_param[i] = FIMD_1_MINUS_COLOR(bg_color);
  682. break;
  683. default:
  684. hw_error("exynos4210.fimd: blend equation coef illegal value\n");
  685. break;
  686. }
  687. }
  688. fg_color = fimd_mult_and_sum_each_byte(bg_color, blend_param[B_COEF],
  689. fg_color, blend_param[A_COEF]);
  690. ret->b = fg_color & 0xFF;
  691. fg_color >>= 8;
  692. ret->g = fg_color & 0xFF;
  693. fg_color >>= 8;
  694. ret->r = fg_color & 0xFF;
  695. ret->a = fimd_mult_and_sum_each_byte(alpha_fg, blend_param[P_COEF],
  696. p_bg.a, blend_param[Q_COEF]);
  697. }
  698. /* These routines read data from video frame buffer in system RAM, convert
  699. * this data to display controller internal representation, if necessary,
  700. * perform pixel blending with data, currently presented in internal buffer.
  701. * Result is stored in display controller internal frame buffer. */
  702. /* Draw line with index in palette table in RAM frame buffer data */
  703. #define DEF_DRAW_LINE_PALETTE(N) \
  704. static void glue(draw_line_palette_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
  705. uint8_t *dst, bool blend) \
  706. { \
  707. int width = w->rightbot_x - w->lefttop_x + 1; \
  708. uint8_t *ifb = dst; \
  709. uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
  710. uint64_t data; \
  711. rgba p, p_old; \
  712. int i; \
  713. do { \
  714. memcpy(&data, src, sizeof(data)); \
  715. src += 8; \
  716. fimd_swap_data(swap, &data); \
  717. for (i = (64 / (N) - 1); i >= 0; i--) { \
  718. w->pixel_to_rgb(w->palette[(data >> ((N) * i)) & \
  719. ((1ULL << (N)) - 1)], &p); \
  720. p.a = w->get_alpha(w, p.a); \
  721. if (blend) { \
  722. ifb += get_pixel_ifb(ifb, &p_old); \
  723. exynos4210_fimd_blend_pixel(w, p_old, &p); \
  724. } \
  725. dst += put_pixel_ifb(p, dst); \
  726. } \
  727. width -= (64 / (N)); \
  728. } while (width > 0); \
  729. }
  730. /* Draw line with direct color value in RAM frame buffer data */
  731. #define DEF_DRAW_LINE_NOPALETTE(N) \
  732. static void glue(draw_line_, N)(Exynos4210fimdWindow *w, uint8_t *src, \
  733. uint8_t *dst, bool blend) \
  734. { \
  735. int width = w->rightbot_x - w->lefttop_x + 1; \
  736. uint8_t *ifb = dst; \
  737. uint8_t swap = (w->wincon & FIMD_WINCON_SWAP) >> FIMD_WINCON_SWAP_SHIFT; \
  738. uint64_t data; \
  739. rgba p, p_old; \
  740. int i; \
  741. do { \
  742. memcpy(&data, src, sizeof(data)); \
  743. src += 8; \
  744. fimd_swap_data(swap, &data); \
  745. for (i = (64 / (N) - 1); i >= 0; i--) { \
  746. w->pixel_to_rgb((data >> ((N) * i)) & ((1ULL << (N)) - 1), &p); \
  747. p.a = w->get_alpha(w, p.a); \
  748. if (blend) { \
  749. ifb += get_pixel_ifb(ifb, &p_old); \
  750. exynos4210_fimd_blend_pixel(w, p_old, &p); \
  751. } \
  752. dst += put_pixel_ifb(p, dst); \
  753. } \
  754. width -= (64 / (N)); \
  755. } while (width > 0); \
  756. }
  757. DEF_DRAW_LINE_PALETTE(1)
  758. DEF_DRAW_LINE_PALETTE(2)
  759. DEF_DRAW_LINE_PALETTE(4)
  760. DEF_DRAW_LINE_PALETTE(8)
  761. DEF_DRAW_LINE_NOPALETTE(8) /* 8bpp mode has palette and non-palette versions */
  762. DEF_DRAW_LINE_NOPALETTE(16)
  763. DEF_DRAW_LINE_NOPALETTE(32)
  764. /* Special draw line routine for window color map case */
  765. static void draw_line_mapcolor(Exynos4210fimdWindow *w, uint8_t *src,
  766. uint8_t *dst, bool blend)
  767. {
  768. rgba p, p_old;
  769. uint8_t *ifb = dst;
  770. int width = w->rightbot_x - w->lefttop_x + 1;
  771. uint32_t map_color = w->winmap & FIMD_WINMAP_COLOR_MASK;
  772. do {
  773. pixel_888_to_rgb(map_color, &p);
  774. p.a = w->get_alpha(w, p.a);
  775. if (blend) {
  776. ifb += get_pixel_ifb(ifb, &p_old);
  777. exynos4210_fimd_blend_pixel(w, p_old, &p);
  778. }
  779. dst += put_pixel_ifb(p, dst);
  780. } while (--width);
  781. }
  782. /* Write RGB to QEMU's GraphicConsole framebuffer */
  783. static int put_to_qemufb_pixel8(const rgba p, uint8_t *d)
  784. {
  785. uint32_t pixel = rgb_to_pixel8(p.r, p.g, p.b);
  786. *(uint8_t *)d = pixel;
  787. return 1;
  788. }
  789. static int put_to_qemufb_pixel15(const rgba p, uint8_t *d)
  790. {
  791. uint32_t pixel = rgb_to_pixel15(p.r, p.g, p.b);
  792. *(uint16_t *)d = pixel;
  793. return 2;
  794. }
  795. static int put_to_qemufb_pixel16(const rgba p, uint8_t *d)
  796. {
  797. uint32_t pixel = rgb_to_pixel16(p.r, p.g, p.b);
  798. *(uint16_t *)d = pixel;
  799. return 2;
  800. }
  801. static int put_to_qemufb_pixel24(const rgba p, uint8_t *d)
  802. {
  803. uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
  804. *(uint8_t *)d++ = (pixel >> 0) & 0xFF;
  805. *(uint8_t *)d++ = (pixel >> 8) & 0xFF;
  806. *(uint8_t *)d++ = (pixel >> 16) & 0xFF;
  807. return 3;
  808. }
  809. static int put_to_qemufb_pixel32(const rgba p, uint8_t *d)
  810. {
  811. uint32_t pixel = rgb_to_pixel24(p.r, p.g, p.b);
  812. *(uint32_t *)d = pixel;
  813. return 4;
  814. }
  815. /* Routine to copy pixel from internal buffer to QEMU buffer */
  816. static int (*put_pixel_toqemu)(const rgba p, uint8_t *pixel);
  817. static inline void fimd_update_putpix_qemu(int bpp)
  818. {
  819. switch (bpp) {
  820. case 8:
  821. put_pixel_toqemu = put_to_qemufb_pixel8;
  822. break;
  823. case 15:
  824. put_pixel_toqemu = put_to_qemufb_pixel15;
  825. break;
  826. case 16:
  827. put_pixel_toqemu = put_to_qemufb_pixel16;
  828. break;
  829. case 24:
  830. put_pixel_toqemu = put_to_qemufb_pixel24;
  831. break;
  832. case 32:
  833. put_pixel_toqemu = put_to_qemufb_pixel32;
  834. break;
  835. default:
  836. hw_error("exynos4210.fimd: unsupported BPP (%d)", bpp);
  837. break;
  838. }
  839. }
  840. /* Routine to copy a line from internal frame buffer to QEMU display */
  841. static void fimd_copy_line_toqemu(int width, uint8_t *src, uint8_t *dst)
  842. {
  843. rgba p;
  844. do {
  845. src += get_pixel_ifb(src, &p);
  846. dst += put_pixel_toqemu(p, dst);
  847. } while (--width);
  848. }
  849. /* Parse BPPMODE_F = WINCON1[5:2] bits */
  850. static void exynos4210_fimd_update_win_bppmode(Exynos4210fimdState *s, int win)
  851. {
  852. Exynos4210fimdWindow *w = &s->window[win];
  853. if (w->winmap & FIMD_WINMAP_EN) {
  854. w->draw_line = draw_line_mapcolor;
  855. return;
  856. }
  857. switch (WIN_BPP_MODE(w)) {
  858. case 0:
  859. w->draw_line = draw_line_palette_1;
  860. w->pixel_to_rgb =
  861. palette_data_format[exynos4210_fimd_palette_format(s, win)];
  862. break;
  863. case 1:
  864. w->draw_line = draw_line_palette_2;
  865. w->pixel_to_rgb =
  866. palette_data_format[exynos4210_fimd_palette_format(s, win)];
  867. break;
  868. case 2:
  869. w->draw_line = draw_line_palette_4;
  870. w->pixel_to_rgb =
  871. palette_data_format[exynos4210_fimd_palette_format(s, win)];
  872. break;
  873. case 3:
  874. w->draw_line = draw_line_palette_8;
  875. w->pixel_to_rgb =
  876. palette_data_format[exynos4210_fimd_palette_format(s, win)];
  877. break;
  878. case 4:
  879. w->draw_line = draw_line_8;
  880. w->pixel_to_rgb = pixel_a232_to_rgb;
  881. break;
  882. case 5:
  883. w->draw_line = draw_line_16;
  884. w->pixel_to_rgb = pixel_565_to_rgb;
  885. break;
  886. case 6:
  887. w->draw_line = draw_line_16;
  888. w->pixel_to_rgb = pixel_a555_to_rgb;
  889. break;
  890. case 7:
  891. w->draw_line = draw_line_16;
  892. w->pixel_to_rgb = pixel_1555_to_rgb;
  893. break;
  894. case 8:
  895. w->draw_line = draw_line_32;
  896. w->pixel_to_rgb = pixel_666_to_rgb;
  897. break;
  898. case 9:
  899. w->draw_line = draw_line_32;
  900. w->pixel_to_rgb = pixel_a665_to_rgb;
  901. break;
  902. case 10:
  903. w->draw_line = draw_line_32;
  904. w->pixel_to_rgb = pixel_a666_to_rgb;
  905. break;
  906. case 11:
  907. w->draw_line = draw_line_32;
  908. w->pixel_to_rgb = pixel_888_to_rgb;
  909. break;
  910. case 12:
  911. w->draw_line = draw_line_32;
  912. w->pixel_to_rgb = pixel_a887_to_rgb;
  913. break;
  914. case 13:
  915. w->draw_line = draw_line_32;
  916. if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
  917. FIMD_WINCON_ALPHA_SEL)) {
  918. w->pixel_to_rgb = pixel_8888_to_rgb;
  919. } else {
  920. w->pixel_to_rgb = pixel_a888_to_rgb;
  921. }
  922. break;
  923. case 14:
  924. w->draw_line = draw_line_16;
  925. if ((w->wincon & FIMD_WINCON_BLD_PIX) && (w->wincon &
  926. FIMD_WINCON_ALPHA_SEL)) {
  927. w->pixel_to_rgb = pixel_4444_to_rgb;
  928. } else {
  929. w->pixel_to_rgb = pixel_a444_to_rgb;
  930. }
  931. break;
  932. case 15:
  933. w->draw_line = draw_line_16;
  934. w->pixel_to_rgb = pixel_555_to_rgb;
  935. break;
  936. }
  937. }
  938. #if EXYNOS4210_FIMD_MODE_TRACE > 0
  939. static const char *exynos4210_fimd_get_bppmode(int mode_code)
  940. {
  941. switch (mode_code) {
  942. case 0:
  943. return "1 bpp";
  944. case 1:
  945. return "2 bpp";
  946. case 2:
  947. return "4 bpp";
  948. case 3:
  949. return "8 bpp (palettized)";
  950. case 4:
  951. return "8 bpp (non-palettized, A: 1-R:2-G:3-B:2)";
  952. case 5:
  953. return "16 bpp (non-palettized, R:5-G:6-B:5)";
  954. case 6:
  955. return "16 bpp (non-palettized, A:1-R:5-G:5-B:5)";
  956. case 7:
  957. return "16 bpp (non-palettized, I :1-R:5-G:5-B:5)";
  958. case 8:
  959. return "Unpacked 18 bpp (non-palettized, R:6-G:6-B:6)";
  960. case 9:
  961. return "Unpacked 18bpp (non-palettized,A:1-R:6-G:6-B:5)";
  962. case 10:
  963. return "Unpacked 19bpp (non-palettized,A:1-R:6-G:6-B:6)";
  964. case 11:
  965. return "Unpacked 24 bpp (non-palettized R:8-G:8-B:8)";
  966. case 12:
  967. return "Unpacked 24 bpp (non-palettized A:1-R:8-G:8-B:7)";
  968. case 13:
  969. return "Unpacked 25 bpp (non-palettized A:1-R:8-G:8-B:8)";
  970. case 14:
  971. return "Unpacked 13 bpp (non-palettized A:1-R:4-G:4-B:4)";
  972. case 15:
  973. return "Unpacked 15 bpp (non-palettized R:5-G:5-B:5)";
  974. default:
  975. return "Non-existing bpp mode";
  976. }
  977. }
  978. static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
  979. int win_num, uint32_t val)
  980. {
  981. Exynos4210fimdWindow *w = &s->window[win_num];
  982. if (w->winmap & FIMD_WINMAP_EN) {
  983. printf("QEMU FIMD: Window %d is mapped with MAPCOLOR=0x%x\n",
  984. win_num, w->winmap & 0xFFFFFF);
  985. return;
  986. }
  987. if ((val != 0xFFFFFFFF) && ((w->wincon >> 2) & 0xF) == ((val >> 2) & 0xF)) {
  988. return;
  989. }
  990. printf("QEMU FIMD: Window %d BPP mode set to %s\n", win_num,
  991. exynos4210_fimd_get_bppmode((val >> 2) & 0xF));
  992. }
  993. #else
  994. static inline void exynos4210_fimd_trace_bppmode(Exynos4210fimdState *s,
  995. int win_num, uint32_t val)
  996. {
  997. }
  998. #endif
  999. static inline int fimd_get_buffer_id(Exynos4210fimdWindow *w)
  1000. {
  1001. switch (w->wincon & FIMD_WINCON_BUFSTATUS) {
  1002. case FIMD_WINCON_BUF0_STAT:
  1003. return 0;
  1004. case FIMD_WINCON_BUF1_STAT:
  1005. return 1;
  1006. case FIMD_WINCON_BUF2_STAT:
  1007. return 2;
  1008. default:
  1009. DPRINT_ERROR("Non-existent buffer index\n");
  1010. return 0;
  1011. }
  1012. }
  1013. static void exynos4210_fimd_invalidate(void *opaque)
  1014. {
  1015. Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
  1016. s->invalidate = true;
  1017. }
  1018. /* Updates specified window's MemorySection based on values of WINCON,
  1019. * VIDOSDA, VIDOSDB, VIDWADDx and SHADOWCON registers */
  1020. static void fimd_update_memory_section(Exynos4210fimdState *s, unsigned win)
  1021. {
  1022. SysBusDevice *sbd = SYS_BUS_DEVICE(s);
  1023. Exynos4210fimdWindow *w = &s->window[win];
  1024. hwaddr fb_start_addr, fb_mapped_len;
  1025. if (!s->enabled || !(w->wincon & FIMD_WINCON_ENWIN) ||
  1026. FIMD_WINDOW_PROTECTED(s->shadowcon, win)) {
  1027. return;
  1028. }
  1029. if (w->host_fb_addr) {
  1030. cpu_physical_memory_unmap(w->host_fb_addr, w->fb_len, 0, 0);
  1031. w->host_fb_addr = NULL;
  1032. w->fb_len = 0;
  1033. }
  1034. fb_start_addr = w->buf_start[fimd_get_buffer_id(w)];
  1035. /* Total number of bytes of virtual screen used by current window */
  1036. w->fb_len = fb_mapped_len = (w->virtpage_width + w->virtpage_offsize) *
  1037. (w->rightbot_y - w->lefttop_y + 1);
  1038. /* TODO: add .exit and unref the region there. Not needed yet since sysbus
  1039. * does not support hot-unplug.
  1040. */
  1041. if (w->mem_section.mr) {
  1042. memory_region_set_log(w->mem_section.mr, false, DIRTY_MEMORY_VGA);
  1043. memory_region_unref(w->mem_section.mr);
  1044. }
  1045. w->mem_section = memory_region_find(sysbus_address_space(sbd),
  1046. fb_start_addr, w->fb_len);
  1047. assert(w->mem_section.mr);
  1048. assert(w->mem_section.offset_within_address_space == fb_start_addr);
  1049. DPRINT_TRACE("Window %u framebuffer changed: address=0x%08x, len=0x%x\n",
  1050. win, fb_start_addr, w->fb_len);
  1051. if (int128_get64(w->mem_section.size) != w->fb_len ||
  1052. !memory_region_is_ram(w->mem_section.mr)) {
  1053. DPRINT_ERROR("Failed to find window %u framebuffer region\n", win);
  1054. goto error_return;
  1055. }
  1056. w->host_fb_addr = cpu_physical_memory_map(fb_start_addr, &fb_mapped_len, 0);
  1057. if (!w->host_fb_addr) {
  1058. DPRINT_ERROR("Failed to map window %u framebuffer\n", win);
  1059. goto error_return;
  1060. }
  1061. if (fb_mapped_len != w->fb_len) {
  1062. DPRINT_ERROR("Window %u mapped framebuffer length is less then "
  1063. "expected\n", win);
  1064. cpu_physical_memory_unmap(w->host_fb_addr, fb_mapped_len, 0, 0);
  1065. goto error_return;
  1066. }
  1067. memory_region_set_log(w->mem_section.mr, true, DIRTY_MEMORY_VGA);
  1068. exynos4210_fimd_invalidate(s);
  1069. return;
  1070. error_return:
  1071. memory_region_unref(w->mem_section.mr);
  1072. w->mem_section.mr = NULL;
  1073. w->mem_section.size = int128_zero();
  1074. w->host_fb_addr = NULL;
  1075. w->fb_len = 0;
  1076. }
  1077. static void exynos4210_fimd_enable(Exynos4210fimdState *s, bool enabled)
  1078. {
  1079. if (enabled && !s->enabled) {
  1080. unsigned w;
  1081. s->enabled = true;
  1082. for (w = 0; w < NUM_OF_WINDOWS; w++) {
  1083. fimd_update_memory_section(s, w);
  1084. }
  1085. }
  1086. s->enabled = enabled;
  1087. DPRINT_TRACE("display controller %s\n", enabled ? "enabled" : "disabled");
  1088. }
  1089. static inline uint32_t unpack_upper_4(uint32_t x)
  1090. {
  1091. return ((x & 0xF00) << 12) | ((x & 0xF0) << 8) | ((x & 0xF) << 4);
  1092. }
  1093. static inline uint32_t pack_upper_4(uint32_t x)
  1094. {
  1095. return (((x & 0xF00000) >> 12) | ((x & 0xF000) >> 8) |
  1096. ((x & 0xF0) >> 4)) & 0xFFF;
  1097. }
  1098. static void exynos4210_fimd_update_irq(Exynos4210fimdState *s)
  1099. {
  1100. if (!(s->vidintcon[0] & FIMD_VIDINT_INTEN)) {
  1101. qemu_irq_lower(s->irq[0]);
  1102. qemu_irq_lower(s->irq[1]);
  1103. qemu_irq_lower(s->irq[2]);
  1104. return;
  1105. }
  1106. if ((s->vidintcon[0] & FIMD_VIDINT_INTFIFOEN) &&
  1107. (s->vidintcon[1] & FIMD_VIDINT_INTFIFOPEND)) {
  1108. qemu_irq_raise(s->irq[0]);
  1109. } else {
  1110. qemu_irq_lower(s->irq[0]);
  1111. }
  1112. if ((s->vidintcon[0] & FIMD_VIDINT_INTFRMEN) &&
  1113. (s->vidintcon[1] & FIMD_VIDINT_INTFRMPEND)) {
  1114. qemu_irq_raise(s->irq[1]);
  1115. } else {
  1116. qemu_irq_lower(s->irq[1]);
  1117. }
  1118. if ((s->vidintcon[0] & FIMD_VIDINT_I80IFDONE) &&
  1119. (s->vidintcon[1] & FIMD_VIDINT_INTI80PEND)) {
  1120. qemu_irq_raise(s->irq[2]);
  1121. } else {
  1122. qemu_irq_lower(s->irq[2]);
  1123. }
  1124. }
  1125. static void exynos4210_update_resolution(Exynos4210fimdState *s)
  1126. {
  1127. DisplaySurface *surface = qemu_console_surface(s->console);
  1128. /* LCD resolution is stored in VIDEO TIME CONTROL REGISTER 2 */
  1129. uint32_t width = ((s->vidtcon[2] >> FIMD_VIDTCON2_HOR_SHIFT) &
  1130. FIMD_VIDTCON2_SIZE_MASK) + 1;
  1131. uint32_t height = ((s->vidtcon[2] >> FIMD_VIDTCON2_VER_SHIFT) &
  1132. FIMD_VIDTCON2_SIZE_MASK) + 1;
  1133. if (s->ifb == NULL || surface_width(surface) != width ||
  1134. surface_height(surface) != height) {
  1135. DPRINT_L1("Resolution changed from %ux%u to %ux%u\n",
  1136. surface_width(surface), surface_height(surface), width, height);
  1137. qemu_console_resize(s->console, width, height);
  1138. s->ifb = g_realloc(s->ifb, width * height * RGBA_SIZE + 1);
  1139. memset(s->ifb, 0, width * height * RGBA_SIZE + 1);
  1140. exynos4210_fimd_invalidate(s);
  1141. }
  1142. }
  1143. static void exynos4210_fimd_update(void *opaque)
  1144. {
  1145. Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
  1146. DisplaySurface *surface;
  1147. Exynos4210fimdWindow *w;
  1148. DirtyBitmapSnapshot *snap;
  1149. int i, line;
  1150. hwaddr fb_line_addr, inc_size;
  1151. int scrn_height;
  1152. int first_line = -1, last_line = -1, scrn_width;
  1153. bool blend = false;
  1154. uint8_t *host_fb_addr;
  1155. bool is_dirty = false;
  1156. const int global_width = (s->vidtcon[2] & FIMD_VIDTCON2_SIZE_MASK) + 1;
  1157. if (!s || !s->console || !s->enabled ||
  1158. surface_bits_per_pixel(qemu_console_surface(s->console)) == 0) {
  1159. return;
  1160. }
  1161. exynos4210_update_resolution(s);
  1162. surface = qemu_console_surface(s->console);
  1163. for (i = 0; i < NUM_OF_WINDOWS; i++) {
  1164. w = &s->window[i];
  1165. if ((w->wincon & FIMD_WINCON_ENWIN) && w->host_fb_addr) {
  1166. scrn_height = w->rightbot_y - w->lefttop_y + 1;
  1167. scrn_width = w->virtpage_width;
  1168. /* Total width of virtual screen page in bytes */
  1169. inc_size = scrn_width + w->virtpage_offsize;
  1170. host_fb_addr = w->host_fb_addr;
  1171. fb_line_addr = w->mem_section.offset_within_region;
  1172. snap = memory_region_snapshot_and_clear_dirty(w->mem_section.mr,
  1173. fb_line_addr, inc_size * scrn_height, DIRTY_MEMORY_VGA);
  1174. for (line = 0; line < scrn_height; line++) {
  1175. is_dirty = memory_region_snapshot_get_dirty(w->mem_section.mr,
  1176. snap, fb_line_addr, scrn_width);
  1177. if (s->invalidate || is_dirty) {
  1178. if (first_line == -1) {
  1179. first_line = line;
  1180. }
  1181. last_line = line;
  1182. w->draw_line(w, host_fb_addr, s->ifb +
  1183. w->lefttop_x * RGBA_SIZE + (w->lefttop_y + line) *
  1184. global_width * RGBA_SIZE, blend);
  1185. }
  1186. host_fb_addr += inc_size;
  1187. fb_line_addr += inc_size;
  1188. is_dirty = false;
  1189. }
  1190. g_free(snap);
  1191. blend = true;
  1192. }
  1193. }
  1194. /* Copy resulting image to QEMU_CONSOLE. */
  1195. if (first_line >= 0) {
  1196. uint8_t *d;
  1197. int bpp;
  1198. bpp = surface_bits_per_pixel(surface);
  1199. fimd_update_putpix_qemu(bpp);
  1200. bpp = (bpp + 1) >> 3;
  1201. d = surface_data(surface);
  1202. for (line = first_line; line <= last_line; line++) {
  1203. fimd_copy_line_toqemu(global_width, s->ifb + global_width * line *
  1204. RGBA_SIZE, d + global_width * line * bpp);
  1205. }
  1206. dpy_gfx_update_full(s->console);
  1207. }
  1208. s->invalidate = false;
  1209. s->vidintcon[1] |= FIMD_VIDINT_INTFRMPEND;
  1210. if ((s->vidcon[0] & FIMD_VIDCON0_ENVID_F) == 0) {
  1211. exynos4210_fimd_enable(s, false);
  1212. }
  1213. exynos4210_fimd_update_irq(s);
  1214. }
  1215. static void exynos4210_fimd_reset(DeviceState *d)
  1216. {
  1217. Exynos4210fimdState *s = EXYNOS4210_FIMD(d);
  1218. unsigned w;
  1219. DPRINT_TRACE("Display controller reset\n");
  1220. /* Set all display controller registers to 0 */
  1221. memset(&s->vidcon, 0, (uint8_t *)&s->window - (uint8_t *)&s->vidcon);
  1222. for (w = 0; w < NUM_OF_WINDOWS; w++) {
  1223. memset(&s->window[w], 0, sizeof(Exynos4210fimdWindow));
  1224. s->window[w].blendeq = 0xC2;
  1225. exynos4210_fimd_update_win_bppmode(s, w);
  1226. exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
  1227. fimd_update_get_alpha(s, w);
  1228. }
  1229. g_free(s->ifb);
  1230. s->ifb = NULL;
  1231. exynos4210_fimd_invalidate(s);
  1232. exynos4210_fimd_enable(s, false);
  1233. /* Some registers have non-zero initial values */
  1234. s->winchmap = 0x7D517D51;
  1235. s->colorgaincon = 0x10040100;
  1236. s->huecoef_cr[0] = s->huecoef_cr[3] = 0x01000100;
  1237. s->huecoef_cb[0] = s->huecoef_cb[3] = 0x01000100;
  1238. s->hueoffset = 0x01800080;
  1239. }
  1240. static void exynos4210_fimd_write(void *opaque, hwaddr offset,
  1241. uint64_t val, unsigned size)
  1242. {
  1243. Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
  1244. unsigned w, i;
  1245. uint32_t old_value;
  1246. DPRINT_L2("write offset 0x%08x, value=%llu(0x%08llx)\n", offset,
  1247. (long long unsigned int)val, (long long unsigned int)val);
  1248. switch (offset) {
  1249. case FIMD_VIDCON0:
  1250. if ((val & FIMD_VIDCON0_ENVID_MASK) == FIMD_VIDCON0_ENVID_MASK) {
  1251. exynos4210_fimd_enable(s, true);
  1252. } else {
  1253. if ((val & FIMD_VIDCON0_ENVID) == 0) {
  1254. exynos4210_fimd_enable(s, false);
  1255. }
  1256. }
  1257. s->vidcon[0] = val;
  1258. break;
  1259. case FIMD_VIDCON1:
  1260. /* Leave read-only bits as is */
  1261. val = (val & (~FIMD_VIDCON1_ROMASK)) |
  1262. (s->vidcon[1] & FIMD_VIDCON1_ROMASK);
  1263. s->vidcon[1] = val;
  1264. break;
  1265. case FIMD_VIDCON2 ... FIMD_VIDCON3:
  1266. s->vidcon[(offset) >> 2] = val;
  1267. break;
  1268. case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
  1269. s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2] = val;
  1270. break;
  1271. case FIMD_WINCON_START ... FIMD_WINCON_END:
  1272. w = (offset - FIMD_WINCON_START) >> 2;
  1273. /* Window's current buffer ID */
  1274. i = fimd_get_buffer_id(&s->window[w]);
  1275. old_value = s->window[w].wincon;
  1276. val = (val & ~FIMD_WINCON_ROMASK) |
  1277. (s->window[w].wincon & FIMD_WINCON_ROMASK);
  1278. if (w == 0) {
  1279. /* Window 0 wincon ALPHA_MUL bit must always be 0 */
  1280. val &= ~FIMD_WINCON_ALPHA_MUL;
  1281. }
  1282. exynos4210_fimd_trace_bppmode(s, w, val);
  1283. switch (val & FIMD_WINCON_BUFSELECT) {
  1284. case FIMD_WINCON_BUF0_SEL:
  1285. val &= ~FIMD_WINCON_BUFSTATUS;
  1286. break;
  1287. case FIMD_WINCON_BUF1_SEL:
  1288. val = (val & ~FIMD_WINCON_BUFSTAT_H) | FIMD_WINCON_BUFSTAT_L;
  1289. break;
  1290. case FIMD_WINCON_BUF2_SEL:
  1291. if (val & FIMD_WINCON_BUFMODE) {
  1292. val = (val & ~FIMD_WINCON_BUFSTAT_L) | FIMD_WINCON_BUFSTAT_H;
  1293. }
  1294. break;
  1295. default:
  1296. break;
  1297. }
  1298. s->window[w].wincon = val;
  1299. exynos4210_fimd_update_win_bppmode(s, w);
  1300. fimd_update_get_alpha(s, w);
  1301. if ((i != fimd_get_buffer_id(&s->window[w])) ||
  1302. (!(old_value & FIMD_WINCON_ENWIN) && (s->window[w].wincon &
  1303. FIMD_WINCON_ENWIN))) {
  1304. fimd_update_memory_section(s, w);
  1305. }
  1306. break;
  1307. case FIMD_SHADOWCON:
  1308. old_value = s->shadowcon;
  1309. s->shadowcon = val;
  1310. for (w = 0; w < NUM_OF_WINDOWS; w++) {
  1311. if (FIMD_WINDOW_PROTECTED(old_value, w) &&
  1312. !FIMD_WINDOW_PROTECTED(s->shadowcon, w)) {
  1313. fimd_update_memory_section(s, w);
  1314. }
  1315. }
  1316. break;
  1317. case FIMD_WINCHMAP:
  1318. s->winchmap = val;
  1319. break;
  1320. case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
  1321. w = (offset - FIMD_VIDOSD_START) >> 4;
  1322. i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
  1323. switch (i) {
  1324. case 0:
  1325. old_value = s->window[w].lefttop_y;
  1326. s->window[w].lefttop_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
  1327. FIMD_VIDOSD_COORD_MASK;
  1328. s->window[w].lefttop_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
  1329. FIMD_VIDOSD_COORD_MASK;
  1330. if (s->window[w].lefttop_y != old_value) {
  1331. fimd_update_memory_section(s, w);
  1332. }
  1333. break;
  1334. case 1:
  1335. old_value = s->window[w].rightbot_y;
  1336. s->window[w].rightbot_x = (val >> FIMD_VIDOSD_HOR_SHIFT) &
  1337. FIMD_VIDOSD_COORD_MASK;
  1338. s->window[w].rightbot_y = (val >> FIMD_VIDOSD_VER_SHIFT) &
  1339. FIMD_VIDOSD_COORD_MASK;
  1340. if (s->window[w].rightbot_y != old_value) {
  1341. fimd_update_memory_section(s, w);
  1342. }
  1343. break;
  1344. case 2:
  1345. if (w == 0) {
  1346. s->window[w].osdsize = val;
  1347. } else {
  1348. s->window[w].alpha_val[0] =
  1349. unpack_upper_4((val & FIMD_VIDOSD_ALPHA_AEN0) >>
  1350. FIMD_VIDOSD_AEN0_SHIFT) |
  1351. (s->window[w].alpha_val[0] & FIMD_VIDALPHA_ALPHA_LOWER);
  1352. s->window[w].alpha_val[1] =
  1353. unpack_upper_4(val & FIMD_VIDOSD_ALPHA_AEN1) |
  1354. (s->window[w].alpha_val[1] & FIMD_VIDALPHA_ALPHA_LOWER);
  1355. }
  1356. break;
  1357. case 3:
  1358. if (w != 1 && w != 2) {
  1359. DPRINT_ERROR("Bad write offset 0x%08x\n", offset);
  1360. return;
  1361. }
  1362. s->window[w].osdsize = val;
  1363. break;
  1364. }
  1365. break;
  1366. case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
  1367. w = (offset - FIMD_VIDWADD0_START) >> 3;
  1368. i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
  1369. if (i == fimd_get_buffer_id(&s->window[w]) &&
  1370. s->window[w].buf_start[i] != val) {
  1371. s->window[w].buf_start[i] = val;
  1372. fimd_update_memory_section(s, w);
  1373. break;
  1374. }
  1375. s->window[w].buf_start[i] = val;
  1376. break;
  1377. case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
  1378. w = (offset - FIMD_VIDWADD1_START) >> 3;
  1379. i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
  1380. s->window[w].buf_end[i] = val;
  1381. break;
  1382. case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
  1383. w = (offset - FIMD_VIDWADD2_START) >> 2;
  1384. if (((val & FIMD_VIDWADD2_PAGEWIDTH) != s->window[w].virtpage_width) ||
  1385. (((val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE) !=
  1386. s->window[w].virtpage_offsize)) {
  1387. s->window[w].virtpage_width = val & FIMD_VIDWADD2_PAGEWIDTH;
  1388. s->window[w].virtpage_offsize =
  1389. (val >> FIMD_VIDWADD2_OFFSIZE_SHIFT) & FIMD_VIDWADD2_OFFSIZE;
  1390. fimd_update_memory_section(s, w);
  1391. }
  1392. break;
  1393. case FIMD_VIDINTCON0:
  1394. s->vidintcon[0] = val;
  1395. break;
  1396. case FIMD_VIDINTCON1:
  1397. s->vidintcon[1] &= ~(val & 7);
  1398. exynos4210_fimd_update_irq(s);
  1399. break;
  1400. case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
  1401. w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
  1402. i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
  1403. s->window[w].keycon[i] = val;
  1404. break;
  1405. case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
  1406. w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
  1407. s->window[w].keyalpha = val;
  1408. break;
  1409. case FIMD_DITHMODE:
  1410. s->dithmode = val;
  1411. break;
  1412. case FIMD_WINMAP_START ... FIMD_WINMAP_END:
  1413. w = (offset - FIMD_WINMAP_START) >> 2;
  1414. old_value = s->window[w].winmap;
  1415. s->window[w].winmap = val;
  1416. if ((val & FIMD_WINMAP_EN) ^ (old_value & FIMD_WINMAP_EN)) {
  1417. exynos4210_fimd_invalidate(s);
  1418. exynos4210_fimd_update_win_bppmode(s, w);
  1419. exynos4210_fimd_trace_bppmode(s, w, 0xFFFFFFFF);
  1420. exynos4210_fimd_update(s);
  1421. }
  1422. break;
  1423. case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
  1424. i = (offset - FIMD_WPALCON_HIGH) >> 2;
  1425. s->wpalcon[i] = val;
  1426. if (s->wpalcon[1] & FIMD_WPALCON_UPDATEEN) {
  1427. for (w = 0; w < NUM_OF_WINDOWS; w++) {
  1428. exynos4210_fimd_update_win_bppmode(s, w);
  1429. fimd_update_get_alpha(s, w);
  1430. }
  1431. }
  1432. break;
  1433. case FIMD_TRIGCON:
  1434. val = (val & ~FIMD_TRIGCON_ROMASK) | (s->trigcon & FIMD_TRIGCON_ROMASK);
  1435. s->trigcon = val;
  1436. break;
  1437. case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
  1438. s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2] = val;
  1439. break;
  1440. case FIMD_COLORGAINCON:
  1441. s->colorgaincon = val;
  1442. break;
  1443. case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
  1444. s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2] = val;
  1445. break;
  1446. case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
  1447. i = (offset - FIMD_SIFCCON0) >> 2;
  1448. if (i != 2) {
  1449. s->sifccon[i] = val;
  1450. }
  1451. break;
  1452. case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
  1453. i = (offset - FIMD_HUECOEFCR_START) >> 2;
  1454. s->huecoef_cr[i] = val;
  1455. break;
  1456. case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
  1457. i = (offset - FIMD_HUECOEFCB_START) >> 2;
  1458. s->huecoef_cb[i] = val;
  1459. break;
  1460. case FIMD_HUEOFFSET:
  1461. s->hueoffset = val;
  1462. break;
  1463. case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
  1464. w = ((offset - FIMD_VIDWALPHA_START) >> 3);
  1465. i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
  1466. if (w == 0) {
  1467. s->window[w].alpha_val[i] = val;
  1468. } else {
  1469. s->window[w].alpha_val[i] = (val & FIMD_VIDALPHA_ALPHA_LOWER) |
  1470. (s->window[w].alpha_val[i] & FIMD_VIDALPHA_ALPHA_UPPER);
  1471. }
  1472. break;
  1473. case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
  1474. s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq = val;
  1475. break;
  1476. case FIMD_BLENDCON:
  1477. old_value = s->blendcon;
  1478. s->blendcon = val;
  1479. if ((s->blendcon & FIMD_ALPHA_8BIT) != (old_value & FIMD_ALPHA_8BIT)) {
  1480. for (w = 0; w < NUM_OF_WINDOWS; w++) {
  1481. fimd_update_get_alpha(s, w);
  1482. }
  1483. }
  1484. break;
  1485. case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
  1486. s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon = val;
  1487. break;
  1488. case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
  1489. s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2] = val;
  1490. break;
  1491. case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
  1492. if (offset & 0x0004) {
  1493. DPRINT_ERROR("bad write offset 0x%08x\n", offset);
  1494. break;
  1495. }
  1496. w = (offset - FIMD_VIDW0ADD0_B2) >> 3;
  1497. if (fimd_get_buffer_id(&s->window[w]) == 2 &&
  1498. s->window[w].buf_start[2] != val) {
  1499. s->window[w].buf_start[2] = val;
  1500. fimd_update_memory_section(s, w);
  1501. break;
  1502. }
  1503. s->window[w].buf_start[2] = val;
  1504. break;
  1505. case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
  1506. if (offset & 0x0004) {
  1507. DPRINT_ERROR("bad write offset 0x%08x\n", offset);
  1508. break;
  1509. }
  1510. s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start = val;
  1511. break;
  1512. case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
  1513. if (offset & 0x0004) {
  1514. DPRINT_ERROR("bad write offset 0x%08x\n", offset);
  1515. break;
  1516. }
  1517. s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end = val;
  1518. break;
  1519. case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
  1520. s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size = val;
  1521. break;
  1522. case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
  1523. w = (offset - FIMD_PAL_MEM_START) >> 10;
  1524. i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
  1525. s->window[w].palette[i] = val;
  1526. break;
  1527. case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
  1528. /* Palette memory aliases for windows 0 and 1 */
  1529. w = (offset - FIMD_PALMEM_AL_START) >> 10;
  1530. i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
  1531. s->window[w].palette[i] = val;
  1532. break;
  1533. default:
  1534. DPRINT_ERROR("bad write offset 0x%08x\n", offset);
  1535. break;
  1536. }
  1537. }
  1538. static uint64_t exynos4210_fimd_read(void *opaque, hwaddr offset,
  1539. unsigned size)
  1540. {
  1541. Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
  1542. int w, i;
  1543. uint32_t ret = 0;
  1544. DPRINT_L2("read offset 0x%08x\n", offset);
  1545. switch (offset) {
  1546. case FIMD_VIDCON0 ... FIMD_VIDCON3:
  1547. return s->vidcon[(offset - FIMD_VIDCON0) >> 2];
  1548. case FIMD_VIDTCON_START ... FIMD_VIDTCON_END:
  1549. return s->vidtcon[(offset - FIMD_VIDTCON_START) >> 2];
  1550. case FIMD_WINCON_START ... FIMD_WINCON_END:
  1551. return s->window[(offset - FIMD_WINCON_START) >> 2].wincon;
  1552. case FIMD_SHADOWCON:
  1553. return s->shadowcon;
  1554. case FIMD_WINCHMAP:
  1555. return s->winchmap;
  1556. case FIMD_VIDOSD_START ... FIMD_VIDOSD_END:
  1557. w = (offset - FIMD_VIDOSD_START) >> 4;
  1558. i = ((offset - FIMD_VIDOSD_START) & 0xF) >> 2;
  1559. switch (i) {
  1560. case 0:
  1561. ret = ((s->window[w].lefttop_x & FIMD_VIDOSD_COORD_MASK) <<
  1562. FIMD_VIDOSD_HOR_SHIFT) |
  1563. (s->window[w].lefttop_y & FIMD_VIDOSD_COORD_MASK);
  1564. break;
  1565. case 1:
  1566. ret = ((s->window[w].rightbot_x & FIMD_VIDOSD_COORD_MASK) <<
  1567. FIMD_VIDOSD_HOR_SHIFT) |
  1568. (s->window[w].rightbot_y & FIMD_VIDOSD_COORD_MASK);
  1569. break;
  1570. case 2:
  1571. if (w == 0) {
  1572. ret = s->window[w].osdsize;
  1573. } else {
  1574. ret = (pack_upper_4(s->window[w].alpha_val[0]) <<
  1575. FIMD_VIDOSD_AEN0_SHIFT) |
  1576. pack_upper_4(s->window[w].alpha_val[1]);
  1577. }
  1578. break;
  1579. case 3:
  1580. if (w != 1 && w != 2) {
  1581. DPRINT_ERROR("bad read offset 0x%08x\n", offset);
  1582. return 0xBAADBAAD;
  1583. }
  1584. ret = s->window[w].osdsize;
  1585. break;
  1586. }
  1587. return ret;
  1588. case FIMD_VIDWADD0_START ... FIMD_VIDWADD0_END:
  1589. w = (offset - FIMD_VIDWADD0_START) >> 3;
  1590. i = ((offset - FIMD_VIDWADD0_START) >> 2) & 1;
  1591. return s->window[w].buf_start[i];
  1592. case FIMD_VIDWADD1_START ... FIMD_VIDWADD1_END:
  1593. w = (offset - FIMD_VIDWADD1_START) >> 3;
  1594. i = ((offset - FIMD_VIDWADD1_START) >> 2) & 1;
  1595. return s->window[w].buf_end[i];
  1596. case FIMD_VIDWADD2_START ... FIMD_VIDWADD2_END:
  1597. w = (offset - FIMD_VIDWADD2_START) >> 2;
  1598. return s->window[w].virtpage_width | (s->window[w].virtpage_offsize <<
  1599. FIMD_VIDWADD2_OFFSIZE_SHIFT);
  1600. case FIMD_VIDINTCON0 ... FIMD_VIDINTCON1:
  1601. return s->vidintcon[(offset - FIMD_VIDINTCON0) >> 2];
  1602. case FIMD_WKEYCON_START ... FIMD_WKEYCON_END:
  1603. w = ((offset - FIMD_WKEYCON_START) >> 3) + 1;
  1604. i = ((offset - FIMD_WKEYCON_START) >> 2) & 1;
  1605. return s->window[w].keycon[i];
  1606. case FIMD_WKEYALPHA_START ... FIMD_WKEYALPHA_END:
  1607. w = ((offset - FIMD_WKEYALPHA_START) >> 2) + 1;
  1608. return s->window[w].keyalpha;
  1609. case FIMD_DITHMODE:
  1610. return s->dithmode;
  1611. case FIMD_WINMAP_START ... FIMD_WINMAP_END:
  1612. return s->window[(offset - FIMD_WINMAP_START) >> 2].winmap;
  1613. case FIMD_WPALCON_HIGH ... FIMD_WPALCON_LOW:
  1614. return s->wpalcon[(offset - FIMD_WPALCON_HIGH) >> 2];
  1615. case FIMD_TRIGCON:
  1616. return s->trigcon;
  1617. case FIMD_I80IFCON_START ... FIMD_I80IFCON_END:
  1618. return s->i80ifcon[(offset - FIMD_I80IFCON_START) >> 2];
  1619. case FIMD_COLORGAINCON:
  1620. return s->colorgaincon;
  1621. case FIMD_LDI_CMDCON0 ... FIMD_LDI_CMDCON1:
  1622. return s->ldi_cmdcon[(offset - FIMD_LDI_CMDCON0) >> 2];
  1623. case FIMD_SIFCCON0 ... FIMD_SIFCCON2:
  1624. i = (offset - FIMD_SIFCCON0) >> 2;
  1625. return s->sifccon[i];
  1626. case FIMD_HUECOEFCR_START ... FIMD_HUECOEFCR_END:
  1627. i = (offset - FIMD_HUECOEFCR_START) >> 2;
  1628. return s->huecoef_cr[i];
  1629. case FIMD_HUECOEFCB_START ... FIMD_HUECOEFCB_END:
  1630. i = (offset - FIMD_HUECOEFCB_START) >> 2;
  1631. return s->huecoef_cb[i];
  1632. case FIMD_HUEOFFSET:
  1633. return s->hueoffset;
  1634. case FIMD_VIDWALPHA_START ... FIMD_VIDWALPHA_END:
  1635. w = ((offset - FIMD_VIDWALPHA_START) >> 3);
  1636. i = ((offset - FIMD_VIDWALPHA_START) >> 2) & 1;
  1637. return s->window[w].alpha_val[i] &
  1638. (w == 0 ? 0xFFFFFF : FIMD_VIDALPHA_ALPHA_LOWER);
  1639. case FIMD_BLENDEQ_START ... FIMD_BLENDEQ_END:
  1640. return s->window[(offset - FIMD_BLENDEQ_START) >> 2].blendeq;
  1641. case FIMD_BLENDCON:
  1642. return s->blendcon;
  1643. case FIMD_WRTQOSCON_START ... FIMD_WRTQOSCON_END:
  1644. return s->window[(offset - FIMD_WRTQOSCON_START) >> 2].rtqoscon;
  1645. case FIMD_I80IFCMD_START ... FIMD_I80IFCMD_END:
  1646. return s->i80ifcmd[(offset - FIMD_I80IFCMD_START) >> 2];
  1647. case FIMD_VIDW0ADD0_B2 ... FIMD_VIDW4ADD0_B2:
  1648. if (offset & 0x0004) {
  1649. break;
  1650. }
  1651. return s->window[(offset - FIMD_VIDW0ADD0_B2) >> 3].buf_start[2];
  1652. case FIMD_SHD_ADD0_START ... FIMD_SHD_ADD0_END:
  1653. if (offset & 0x0004) {
  1654. break;
  1655. }
  1656. return s->window[(offset - FIMD_SHD_ADD0_START) >> 3].shadow_buf_start;
  1657. case FIMD_SHD_ADD1_START ... FIMD_SHD_ADD1_END:
  1658. if (offset & 0x0004) {
  1659. break;
  1660. }
  1661. return s->window[(offset - FIMD_SHD_ADD1_START) >> 3].shadow_buf_end;
  1662. case FIMD_SHD_ADD2_START ... FIMD_SHD_ADD2_END:
  1663. return s->window[(offset - FIMD_SHD_ADD2_START) >> 2].shadow_buf_size;
  1664. case FIMD_PAL_MEM_START ... FIMD_PAL_MEM_END:
  1665. w = (offset - FIMD_PAL_MEM_START) >> 10;
  1666. i = ((offset - FIMD_PAL_MEM_START) >> 2) & 0xFF;
  1667. return s->window[w].palette[i];
  1668. case FIMD_PALMEM_AL_START ... FIMD_PALMEM_AL_END:
  1669. /* Palette aliases for win 0,1 */
  1670. w = (offset - FIMD_PALMEM_AL_START) >> 10;
  1671. i = ((offset - FIMD_PALMEM_AL_START) >> 2) & 0xFF;
  1672. return s->window[w].palette[i];
  1673. }
  1674. DPRINT_ERROR("bad read offset 0x%08x\n", offset);
  1675. return 0xBAADBAAD;
  1676. }
  1677. static const MemoryRegionOps exynos4210_fimd_mmio_ops = {
  1678. .read = exynos4210_fimd_read,
  1679. .write = exynos4210_fimd_write,
  1680. .valid = {
  1681. .min_access_size = 4,
  1682. .max_access_size = 4,
  1683. .unaligned = false
  1684. },
  1685. .endianness = DEVICE_NATIVE_ENDIAN,
  1686. };
  1687. static int exynos4210_fimd_load(void *opaque, int version_id)
  1688. {
  1689. Exynos4210fimdState *s = (Exynos4210fimdState *)opaque;
  1690. int w;
  1691. if (version_id != 1) {
  1692. return -EINVAL;
  1693. }
  1694. for (w = 0; w < NUM_OF_WINDOWS; w++) {
  1695. exynos4210_fimd_update_win_bppmode(s, w);
  1696. fimd_update_get_alpha(s, w);
  1697. fimd_update_memory_section(s, w);
  1698. }
  1699. /* Redraw the whole screen */
  1700. exynos4210_update_resolution(s);
  1701. exynos4210_fimd_invalidate(s);
  1702. exynos4210_fimd_enable(s, (s->vidcon[0] & FIMD_VIDCON0_ENVID_MASK) ==
  1703. FIMD_VIDCON0_ENVID_MASK);
  1704. return 0;
  1705. }
  1706. static const VMStateDescription exynos4210_fimd_window_vmstate = {
  1707. .name = "exynos4210.fimd_window",
  1708. .version_id = 1,
  1709. .minimum_version_id = 1,
  1710. .fields = (VMStateField[]) {
  1711. VMSTATE_UINT32(wincon, Exynos4210fimdWindow),
  1712. VMSTATE_UINT32_ARRAY(buf_start, Exynos4210fimdWindow, 3),
  1713. VMSTATE_UINT32_ARRAY(buf_end, Exynos4210fimdWindow, 3),
  1714. VMSTATE_UINT32_ARRAY(keycon, Exynos4210fimdWindow, 2),
  1715. VMSTATE_UINT32(keyalpha, Exynos4210fimdWindow),
  1716. VMSTATE_UINT32(winmap, Exynos4210fimdWindow),
  1717. VMSTATE_UINT32(blendeq, Exynos4210fimdWindow),
  1718. VMSTATE_UINT32(rtqoscon, Exynos4210fimdWindow),
  1719. VMSTATE_UINT32_ARRAY(palette, Exynos4210fimdWindow, 256),
  1720. VMSTATE_UINT32(shadow_buf_start, Exynos4210fimdWindow),
  1721. VMSTATE_UINT32(shadow_buf_end, Exynos4210fimdWindow),
  1722. VMSTATE_UINT32(shadow_buf_size, Exynos4210fimdWindow),
  1723. VMSTATE_UINT16(lefttop_x, Exynos4210fimdWindow),
  1724. VMSTATE_UINT16(lefttop_y, Exynos4210fimdWindow),
  1725. VMSTATE_UINT16(rightbot_x, Exynos4210fimdWindow),
  1726. VMSTATE_UINT16(rightbot_y, Exynos4210fimdWindow),
  1727. VMSTATE_UINT32(osdsize, Exynos4210fimdWindow),
  1728. VMSTATE_UINT32_ARRAY(alpha_val, Exynos4210fimdWindow, 2),
  1729. VMSTATE_UINT16(virtpage_width, Exynos4210fimdWindow),
  1730. VMSTATE_UINT16(virtpage_offsize, Exynos4210fimdWindow),
  1731. VMSTATE_END_OF_LIST()
  1732. }
  1733. };
  1734. static const VMStateDescription exynos4210_fimd_vmstate = {
  1735. .name = "exynos4210.fimd",
  1736. .version_id = 1,
  1737. .minimum_version_id = 1,
  1738. .post_load = exynos4210_fimd_load,
  1739. .fields = (VMStateField[]) {
  1740. VMSTATE_UINT32_ARRAY(vidcon, Exynos4210fimdState, 4),
  1741. VMSTATE_UINT32_ARRAY(vidtcon, Exynos4210fimdState, 4),
  1742. VMSTATE_UINT32(shadowcon, Exynos4210fimdState),
  1743. VMSTATE_UINT32(winchmap, Exynos4210fimdState),
  1744. VMSTATE_UINT32_ARRAY(vidintcon, Exynos4210fimdState, 2),
  1745. VMSTATE_UINT32(dithmode, Exynos4210fimdState),
  1746. VMSTATE_UINT32_ARRAY(wpalcon, Exynos4210fimdState, 2),
  1747. VMSTATE_UINT32(trigcon, Exynos4210fimdState),
  1748. VMSTATE_UINT32_ARRAY(i80ifcon, Exynos4210fimdState, 4),
  1749. VMSTATE_UINT32(colorgaincon, Exynos4210fimdState),
  1750. VMSTATE_UINT32_ARRAY(ldi_cmdcon, Exynos4210fimdState, 2),
  1751. VMSTATE_UINT32_ARRAY(sifccon, Exynos4210fimdState, 3),
  1752. VMSTATE_UINT32_ARRAY(huecoef_cr, Exynos4210fimdState, 4),
  1753. VMSTATE_UINT32_ARRAY(huecoef_cb, Exynos4210fimdState, 4),
  1754. VMSTATE_UINT32(hueoffset, Exynos4210fimdState),
  1755. VMSTATE_UINT32_ARRAY(i80ifcmd, Exynos4210fimdState, 12),
  1756. VMSTATE_UINT32(blendcon, Exynos4210fimdState),
  1757. VMSTATE_STRUCT_ARRAY(window, Exynos4210fimdState, 5, 1,
  1758. exynos4210_fimd_window_vmstate, Exynos4210fimdWindow),
  1759. VMSTATE_END_OF_LIST()
  1760. }
  1761. };
  1762. static const GraphicHwOps exynos4210_fimd_ops = {
  1763. .invalidate = exynos4210_fimd_invalidate,
  1764. .gfx_update = exynos4210_fimd_update,
  1765. };
  1766. static void exynos4210_fimd_init(Object *obj)
  1767. {
  1768. Exynos4210fimdState *s = EXYNOS4210_FIMD(obj);
  1769. SysBusDevice *dev = SYS_BUS_DEVICE(obj);
  1770. s->ifb = NULL;
  1771. sysbus_init_irq(dev, &s->irq[0]);
  1772. sysbus_init_irq(dev, &s->irq[1]);
  1773. sysbus_init_irq(dev, &s->irq[2]);
  1774. memory_region_init_io(&s->iomem, obj, &exynos4210_fimd_mmio_ops, s,
  1775. "exynos4210.fimd", FIMD_REGS_SIZE);
  1776. sysbus_init_mmio(dev, &s->iomem);
  1777. }
  1778. static void exynos4210_fimd_realize(DeviceState *dev, Error **errp)
  1779. {
  1780. Exynos4210fimdState *s = EXYNOS4210_FIMD(dev);
  1781. s->console = graphic_console_init(dev, 0, &exynos4210_fimd_ops, s);
  1782. }
  1783. static void exynos4210_fimd_class_init(ObjectClass *klass, void *data)
  1784. {
  1785. DeviceClass *dc = DEVICE_CLASS(klass);
  1786. dc->vmsd = &exynos4210_fimd_vmstate;
  1787. dc->reset = exynos4210_fimd_reset;
  1788. dc->realize = exynos4210_fimd_realize;
  1789. }
  1790. static const TypeInfo exynos4210_fimd_info = {
  1791. .name = TYPE_EXYNOS4210_FIMD,
  1792. .parent = TYPE_SYS_BUS_DEVICE,
  1793. .instance_size = sizeof(Exynos4210fimdState),
  1794. .instance_init = exynos4210_fimd_init,
  1795. .class_init = exynos4210_fimd_class_init,
  1796. };
  1797. static void exynos4210_fimd_register_types(void)
  1798. {
  1799. type_register_static(&exynos4210_fimd_info);
  1800. }
  1801. type_init(exynos4210_fimd_register_types)