exynos4210_fimd.c 69 KB

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