upload tizen1.0 source
[kernel/linux-2.6.36.git] / drivers / media / video / samsung / tvout / hw_if / hdmi.c
1 /* linux/drivers/media/video/samsung/tvout/hw_if/hdmi.c
2  *
3  * Copyright (c) 2009 Samsung Electronics
4  *              http://www.samsung.com/
5  *
6  * Functions for HDMI of Samsung TVOUT driver
7  *
8  * This program is free software; you can redistribute it and/or modify
9  * it under the terms of the GNU General Public License version 2 as
10  * published by the Free Software Foundation.
11  */
12
13 #include <linux/io.h>
14 #include <linux/delay.h>
15
16 #include <mach/map.h>
17 #include <mach/regs-hdmi.h>
18
19 #ifdef CONFIG_CPU_S5PV210
20 #include <mach/pd.h>
21 #endif
22
23 #include "../s5p_tvout_common_lib.h"
24 #include "hw_if.h"
25
26 #undef tvout_dbg
27
28 #ifdef CONFIG_HDMI_DEBUG
29 #define tvout_dbg(fmt, ...)                                     \
30                 printk(KERN_INFO "\t\t[HDMI] %s(): " fmt,       \
31                         __func__, ##__VA_ARGS__)
32 #else
33 #define tvout_dbg(fmt, ...)
34 #endif
35
36
37 /****************************************
38  * Definitions for HDMI_PHY
39  ***************************************/
40
41 #define PHY_I2C_ADDRESS         0x70
42 #define PHY_REG_MODE_SET_DONE   0x1F
43
44 #define I2C_ACK                 (1 << 7)
45 #define I2C_INT                 (1 << 5)
46 #define I2C_PEND                (1 << 4)
47 #define I2C_INT_CLEAR           (0 << 4)
48 #define I2C_CLK                 (0x41)
49 #define I2C_CLK_PEND_INT        (I2C_CLK | I2C_INT_CLEAR | I2C_INT)
50 #define I2C_ENABLE              (1 << 4)
51 #define I2C_START               (1 << 5)
52 #define I2C_MODE_MTX            0xC0
53 #define I2C_MODE_MRX            0x80
54 #define I2C_IDLE                0
55
56 #define STATE_IDLE              0
57 #define STATE_TX_EDDC_SEGADDR   1
58 #define STATE_TX_EDDC_SEGNUM    2
59 #define STATE_TX_DDC_ADDR       3
60 #define STATE_TX_DDC_OFFSET     4
61 #define STATE_RX_DDC_ADDR       5
62 #define STATE_RX_DDC_DATA       6
63 #define STATE_RX_ADDR           7
64 #define STATE_RX_DATA           8
65 #define STATE_TX_ADDR           9
66 #define STATE_TX_DATA           10
67 #define STATE_TX_STOP           11
68 #define STATE_RX_STOP           12
69
70
71
72
73 static struct {
74         s32     state;
75         u8      *buffer;
76         s32     bytes;
77 } i2c_hdmi_phy_context;
78
79
80
81
82 /****************************************
83  * Definitions for HDMI
84  ***************************************/
85 #define HDMI_IRQ_TOTAL_NUM      6
86
87
88 /* private data area */
89 void __iomem    *hdmi_base;
90 void __iomem    *i2c_hdmi_phy_base;
91
92 irqreturn_t     (*s5p_hdmi_isr_ftn[HDMI_IRQ_TOTAL_NUM])(int irq, void *);
93 spinlock_t      lock_hdmi;
94
95 static const u8 phy_config[][3][32] = {
96         { /* freq = 25.200 MHz */
97                 {
98                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
99                         0x6B, 0x10, 0x02, 0x51, 0x5f, 0xF1, 0x54, 0x7e,
100                         0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
101                         0x22, 0x40, 0xf3, 0x26, 0x00, 0x00, 0x00, 0x80,
102                 }, {
103                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
104                         0x6B, 0x10, 0x02, 0x51, 0x9f, 0xF6, 0x54, 0x9e,
105                         0x84, 0x00, 0x32, 0x38, 0x00, 0xB8, 0x10, 0xE0,
106                         0x22, 0x40, 0xc2, 0x26, 0x00, 0x00, 0x00, 0x80,
107                 }, {
108                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
109                         0x6B, 0x10, 0x02, 0x51, 0xFf, 0xF3, 0x54, 0xbd,
110                         0x84, 0x00, 0x30, 0x38, 0x00, 0xA4, 0x10, 0xE0,
111                         0x22, 0x40, 0xa2, 0x26, 0x00, 0x00, 0x00, 0x80,
112                 },
113         }, { /* freq = 25.175 MHz */
114                 {
115                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x1e, 0x20,
116                         0x6B, 0x50, 0x10, 0x51, 0xf1, 0x31, 0x54, 0xbd,
117                         0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
118                         0x22, 0x40, 0xf3, 0x26, 0x00, 0x00, 0x00, 0x80,
119                 }, {
120                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x2b, 0x40,
121                         0x6B, 0x50, 0x10, 0x51, 0xF2, 0x32, 0x54, 0xec,
122                         0x84, 0x00, 0x10, 0x38, 0x00, 0xB8, 0x10, 0xE0,
123                         0x22, 0x40, 0xc2, 0x26, 0x00, 0x00, 0x00, 0x80,
124                 }, {
125                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x1e, 0x20,
126                         0x6B, 0x10, 0x02, 0x51, 0xf1, 0x31, 0x54, 0xbd,
127                         0x84, 0x00, 0x10, 0x38, 0x00, 0xA4, 0x10, 0xE0,
128                         0x22, 0x40, 0xa2, 0x26, 0x00, 0x00, 0x00, 0x80,
129                 },
130         }, { /* freq = 27 MHz */
131                 {
132                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
133                         0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
134                         0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
135                         0x22, 0x40, 0xe3, 0x26, 0x00, 0x00, 0x00, 0x80,
136                 }, {
137                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x02, 0x08,
138                         0x6A, 0x10, 0x02, 0x51, 0xCf, 0xF1, 0x54, 0xa9,
139                         0x84, 0x00, 0x10, 0x38, 0x00, 0xB8, 0x10, 0xE0,
140                         0x22, 0x40, 0xb5, 0x26, 0x00, 0x00, 0x00, 0x80,
141                 }, {
142                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xfc, 0x08,
143                         0x6B, 0x10, 0x02, 0x51, 0x2f, 0xF2, 0x54, 0xcb,
144                         0x84, 0x00, 0x10, 0x38, 0x00, 0xA4, 0x10, 0xE0,
145                         0x22, 0x40, 0x97, 0x26, 0x00, 0x00, 0x00, 0x80,
146                 },
147         }, { /* freq = 27.027 MHz */
148                 {
149                         0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
150                         0x6B, 0x10, 0x02, 0x51, 0xDf, 0xF2, 0x54, 0x87,
151                         0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
152                         0x22, 0x40, 0xe2, 0x26, 0x00, 0x00, 0x00, 0x80,
153                 }, {
154                         0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x31, 0x50,
155                         0x6B, 0x10, 0x02, 0x51, 0x8f, 0xF3, 0x54, 0xa9,
156                         0x84, 0x00, 0x30, 0x38, 0x00, 0xB8, 0x10, 0xE0,
157                         0x22, 0x40, 0xb5, 0x26, 0x00, 0x00, 0x00, 0x80,
158                 }, {
159                         0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0x1b, 0x64,
160                         0x6F, 0x10, 0x02, 0x51, 0x7f, 0xF8, 0x54, 0xcb,
161                         0x84, 0x00, 0x32, 0x38, 0x00, 0xA4, 0x10, 0xE0,
162                         0x22, 0x40, 0x97, 0x26, 0x00, 0x00, 0x00, 0x80,
163                 },
164         }, { /* freq = 54 MHz */
165                 {
166                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
167                         0x6B, 0x10, 0x01, 0x51, 0xDf, 0xF2, 0x54, 0x87,
168                         0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
169                         0x22, 0x40, 0xe3, 0x26, 0x01, 0x00, 0x00, 0x80,
170                 }, {
171                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x02, 0x08,
172                         0x6A, 0x10, 0x01, 0x51, 0xCf, 0xF1, 0x54, 0xa9,
173                         0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, 0x10, 0xE0,
174                         0x22, 0x40, 0xb5, 0x26, 0x01, 0x00, 0x00, 0x80,
175                 }, {
176                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xfc, 0x08,
177                         0x6B, 0x10, 0x01, 0x51, 0x2f, 0xF2, 0x54, 0xcb,
178                         0x84, 0x00, 0x10, 0x38, 0x00, 0xE4, 0x10, 0xE0,
179                         0x22, 0x40, 0x97, 0x26, 0x01, 0x00, 0x00, 0x80,
180                 },
181         }, { /* freq = 54.054 MHz */
182                 {
183                         0x01, 0x05, 0x00, 0xd4, 0x10, 0x9C, 0x09, 0x64,
184                         0x6B, 0x10, 0x01, 0x51, 0xDf, 0xF2, 0x54, 0x87,
185                         0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
186                         0x22, 0x40, 0xe2, 0x26, 0x01, 0x00, 0x00, 0x80,
187                 }, {
188                         0x01, 0x05, 0x00, 0xd4, 0x10, 0x9C, 0x31, 0x50,
189                         0x6B, 0x10, 0x01, 0x51, 0x8f, 0xF3, 0x54, 0xa9,
190                         0x84, 0x00, 0x30, 0x38, 0x00, 0xF8, 0x10, 0xE0,
191                         0x22, 0x40, 0xb5, 0x26, 0x01, 0x00, 0x00, 0x80,
192                 }, {
193                         0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0x1b, 0x64,
194                         0x6F, 0x10, 0x01, 0x51, 0x7f, 0xF8, 0x54, 0xcb,
195                         0x84, 0x00, 0x32, 0x38, 0x00, 0xE4, 0x10, 0xE0,
196                         0x22, 0x40, 0x97, 0x26, 0x01, 0x00, 0x00, 0x80,
197                 },
198         }, { /* freq = 74.250 MHz */
199                 {
200                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
201                         0x6A, 0x10, 0x01, 0x51, 0xff, 0xF1, 0x54, 0xba,
202                         0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
203                         0x22, 0x40, 0xa4, 0x26, 0x01, 0x00, 0x00, 0x80,
204                 }, {
205                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xd6, 0x40,
206                         0x6B, 0x10, 0x01, 0x51, 0x7f, 0xF2, 0x54, 0xe8,
207                         0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, 0x10, 0xE0,
208                         0x22, 0x40, 0x83, 0x26, 0x01, 0x00, 0x00, 0x80,
209                 }, {
210                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x34, 0x40,
211                         0x6B, 0x10, 0x01, 0x51, 0xef, 0xF2, 0x54, 0x16,
212                         0x85, 0x00, 0x10, 0x38, 0x00, 0xE4, 0x10, 0xE0,
213                         0x22, 0x40, 0xdc, 0x26, 0x02, 0x00, 0x00, 0x80,
214                 },
215         }, { /* freq = 74.176 MHz */
216                 {
217                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
218                         0x6D, 0x10, 0x01, 0x51, 0xef, 0xF3, 0x54, 0xb9,
219                         0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
220                         0x22, 0x40, 0xa5, 0x26, 0x01, 0x00, 0x00, 0x80,
221                 }, {
222                         0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0xab, 0x5B,
223                         0x6F, 0x10, 0x01, 0x51, 0xbf, 0xF9, 0x54, 0xe8,
224                         0x84, 0x00, 0x32, 0x38, 0x00, 0xF8, 0x10, 0xE0,
225                         0x22, 0x40, 0x84, 0x26, 0x01, 0x00, 0x00, 0x80,
226                 }, {
227                         0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0xcd, 0x5B,
228                         0x6F, 0x10, 0x01, 0x51, 0xdf, 0xF5, 0x54, 0x16,
229                         0x85, 0x00, 0x30, 0x38, 0x00, 0xE4, 0x10, 0xE0,
230                         0x22, 0x40, 0xdc, 0x26, 0x02, 0x00, 0x00, 0x80,
231                 },
232         }, { /* freq = 148.500 MHz  - Pre-emph + Higher Tx amp. */
233                 {
234                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf8, 0x40,
235                         0x6A, 0x18, 0x00, 0x51, 0xff, 0xF1, 0x54, 0xba,
236                         0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
237                         0x22, 0x40, 0xa4, 0x26, 0x02, 0x00, 0x00, 0x80,
238                 }, {
239                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xd6, 0x40,
240                         0x6B, 0x18, 0x00, 0x51, 0x7f, 0xF2, 0x54, 0xe8,
241                         0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, 0x10, 0xE0,
242                         0x23, 0x41, 0x83, 0x26, 0x02, 0x00, 0x00, 0x80,
243                 }, {
244                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x34, 0x40,
245                         0x6B, 0x18, 0x00, 0x51, 0xef, 0xF2, 0x54, 0x16,
246                         0x85, 0x00, 0x10, 0x38, 0x00, 0xE4, 0x10, 0xE0,
247                         0x23, 0x41, 0x6d, 0x26, 0x02, 0x00, 0x00, 0x80,
248                 },
249         }, { /* freq = 148.352 MHz */
250                 {
251                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xef, 0x5B,
252                         0x6D, 0x18, 0x00, 0x51, 0xef, 0xF3, 0x54, 0xb9,
253                         0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
254                         0x22, 0x40, 0xa5, 0x26, 0x02, 0x00, 0x00, 0x80,
255                 }, {
256                         0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0xab, 0x5B,
257                         0x6F, 0x18, 0x00, 0x51, 0xbf, 0xF9, 0x54, 0xe8,
258                         0x84, 0x00, 0x32, 0x38, 0x00, 0xF8, 0x10, 0xE0,
259                         0x23, 0x41, 0x84, 0x26, 0x02, 0x00, 0x00, 0x80,
260                 }, {
261                         0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0xcd, 0x5B,
262                         0x6F, 0x18, 0x00, 0x51, 0xdf, 0xF5, 0x54, 0x16,
263                         0x85, 0x00, 0x30, 0x38, 0x00, 0xE4, 0x10, 0xE0,
264                         0x23, 0x41, 0x6d, 0x26, 0x02, 0x00, 0x00, 0x80,
265                 },
266         }, { /* freq = 108.108 MHz */
267                 {
268                         0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x09, 0x64,
269                         0x6B, 0x18, 0x00, 0x51, 0xDf, 0xF2, 0x54, 0x87,
270                         0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
271                         0x22, 0x40, 0xe2, 0x26, 0x02, 0x00, 0x00, 0x80,
272                 }, {
273                         0x01, 0x05, 0x00, 0xD4, 0x10, 0x9C, 0x31, 0x50,
274                         0x6D, 0x18, 0x00, 0x51, 0x8f, 0xF3, 0x54, 0xa9,
275                         0x84, 0x00, 0x30, 0x38, 0x00, 0xF8, 0x10, 0xE0,
276                         0x22, 0x40, 0xb5, 0x26, 0x02, 0x00, 0x00, 0x80,
277                 }, {
278                         0x01, 0x05, 0x00, 0x10, 0x10, 0x9C, 0x1b, 0x64,
279                         0x6F, 0x18, 0x00, 0x51, 0x7f, 0xF8, 0x54, 0xcb,
280                         0x84, 0x00, 0x32, 0x38, 0x00, 0xE4, 0x10, 0xE0,
281                         0x22, 0x40, 0x97, 0x26, 0x02, 0x00, 0x00, 0x80,
282                 },
283         }, { /* freq = 72 MHz */
284                 {
285                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
286                         0x6B, 0x10, 0x01, 0x51, 0xEf, 0xF1, 0x54, 0xb4,
287                         0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
288                         0x22, 0x40, 0xaa, 0x26, 0x01, 0x00, 0x00, 0x80,
289                 }, {
290                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
291                         0x6F, 0x10, 0x01, 0x51, 0xBf, 0xF4, 0x54, 0xe1,
292                         0x84, 0x00, 0x30, 0x38, 0x00, 0xF8, 0x10, 0xE0,
293                         0x22, 0x40, 0x88, 0x26, 0x01, 0x00, 0x00, 0x80,
294                 }, {
295                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
296                         0x6B, 0x18, 0x00, 0x51, 0xDf, 0xF2, 0x54, 0x87,
297                         0x84, 0x00, 0x30, 0x38, 0x00, 0xE4, 0x10, 0xE0,
298                         0x22, 0x40, 0xe3, 0x26, 0x02, 0x00, 0x00, 0x80,
299                 },
300         }, { /* freq = 25 MHz */
301                 {
302                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x20, 0x40,
303                         0x6B, 0x50, 0x10, 0x51, 0xff, 0xF1, 0x54, 0xbc,
304                         0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
305                         0x22, 0x40, 0xf5, 0x26, 0x00, 0x00, 0x00, 0x80,
306                 }, {
307                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x08, 0x40,
308                         0x6B, 0x50, 0x10, 0x51, 0x7f, 0xF2, 0x54, 0xea,
309                         0x84, 0x00, 0x10, 0x38, 0x00, 0xB8, 0x10, 0xE0,
310                         0x22, 0x40, 0xc4, 0x26, 0x00, 0x00, 0x00, 0x80,
311                 }, {
312                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x20, 0x40,
313                         0x6B, 0x10, 0x02, 0x51, 0xff, 0xF1, 0x54, 0xbc,
314                         0x84, 0x00, 0x10, 0x38, 0x00, 0xA4, 0x10, 0xE0,
315                         0x22, 0x40, 0xa3, 0x26, 0x00, 0x00, 0x00, 0x80,
316                 },
317         }, { /* freq = 65 MHz */
318                 {
319                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x02, 0x0c,
320                         0x6B, 0x10, 0x01, 0x51, 0xBf, 0xF1, 0x54, 0xa3,
321                         0x84, 0x00, 0x10, 0x38, 0x00, 0x08, 0x10, 0xE0,
322                         0x22, 0x40, 0xbc, 0x26, 0x01, 0x00, 0x00, 0x80,
323                 }, {
324                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xf2, 0x30,
325                         0x6A, 0x10, 0x01, 0x51, 0x2f, 0xF2, 0x54, 0xcb,
326                         0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, 0x10, 0xE0,
327                         0x22, 0x40, 0x96, 0x26, 0x01, 0x00, 0x00, 0x80,
328                 }, {
329                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xd0, 0x40,
330                         0x6B, 0x10, 0x01, 0x51, 0x9f, 0xF2, 0x54, 0xf4,
331                         0x84, 0x00, 0x10, 0x38, 0x00, 0xE4, 0x10, 0xE0,
332                         0x22, 0x40, 0x7D, 0x26, 0x01, 0x00, 0x00, 0x80,
333                 },
334         }, { /* freq = 108 MHz */
335                 {
336                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
337                         0x6D, 0x18, 0x00, 0x51, 0xDf, 0xF2, 0x54, 0x87,
338                         0x84, 0x00, 0x30, 0x38, 0x00, 0x08, 0x10, 0xE0,
339                         0x22, 0x40, 0xe3, 0x26, 0x02, 0x00, 0x00, 0x80,
340                 }, {
341                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x02, 0x08,
342                         0x6A, 0x18, 0x00, 0x51, 0xCf, 0xF1, 0x54, 0xa9,
343                         0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, 0x10, 0xE0,
344                         0x22, 0x40, 0xb5, 0x26, 0x02, 0x00, 0x00, 0x80,
345                 }, {
346                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xfc, 0x08,
347                         0x6B, 0x18, 0x00, 0x51, 0x2f, 0xF2, 0x54, 0xcb,
348                         0x84, 0x00, 0x10, 0x38, 0x00, 0xE4, 0x10, 0xE0,
349                         0x22, 0x40, 0x97, 0x26, 0x02, 0x00, 0x00, 0x80,
350                 },
351         }, { /* freq = 162 MHz */
352                 {
353                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x1C, 0x30, 0x40,
354                         0x6F, 0x18, 0x00, 0x51, 0x7f, 0xF8, 0x54, 0xcb,
355                         0x84, 0x00, 0x32, 0x38, 0x00, 0x08, 0x10, 0xE0,
356                         0x22, 0x40, 0x97, 0x26, 0x02, 0x00, 0x00, 0x80,
357                 }, {
358                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0x18, 0x40,
359                         0x6B, 0x18, 0x00, 0x51, 0xAf, 0xF2, 0x54, 0xfd,
360                         0x84, 0x00, 0x10, 0x38, 0x00, 0xF8, 0x10, 0xE0,
361                         0x23, 0x41, 0x78, 0x26, 0x02, 0x00, 0x00, 0x80,
362                 }, {
363                         0x01, 0x05, 0x00, 0xD8, 0x10, 0x9C, 0xd0, 0x40,
364                         0x6B, 0x18, 0x00, 0x51, 0x3f, 0xF3, 0x54, 0x30,
365                         0x85, 0x00, 0x10, 0x38, 0x00, 0xE4, 0x10, 0xE0,
366                         0x23, 0x41, 0x64, 0x26, 0x02, 0x00, 0x00, 0x80,
367                 },
368         },
369 };
370
371
372 static void s5p_hdmi_reg_core_reset(void)
373 {
374         writeb(0x0, hdmi_base + S5P_HDMI_CORE_RSTOUT);
375
376         mdelay(10);
377
378         writeb(0x1, hdmi_base + S5P_HDMI_CORE_RSTOUT);
379 }
380
381 static s32 s5p_hdmi_i2c_phy_interruptwait(void)
382 {
383         u8 status, reg;
384         s32 retval = 0;
385
386         do {
387                 status = readb(i2c_hdmi_phy_base + HDMI_I2C_CON);
388
389                 if (status & I2C_PEND) {
390                         reg = readb(i2c_hdmi_phy_base + HDMI_I2C_STAT);
391                         break;
392                 }
393
394         } while (1);
395
396         return retval;
397 }
398
399 static s32 s5p_hdmi_i2c_phy_read(u8 addr, u8 nbytes, u8 *buffer)
400 {
401         u8 reg;
402         s32 ret = 0;
403         u32 proc = true;
404
405         i2c_hdmi_phy_context.state = STATE_RX_ADDR;
406         i2c_hdmi_phy_context.buffer = buffer;
407         i2c_hdmi_phy_context.bytes = nbytes;
408
409         writeb(I2C_CLK | I2C_INT | I2C_ACK, i2c_hdmi_phy_base + HDMI_I2C_CON);
410         writeb(I2C_ENABLE | I2C_MODE_MRX, i2c_hdmi_phy_base + HDMI_I2C_STAT);
411         writeb(addr & 0xFE, i2c_hdmi_phy_base + HDMI_I2C_DS);
412         writeb(I2C_ENABLE | I2C_START | I2C_MODE_MRX,
413                                 i2c_hdmi_phy_base + HDMI_I2C_STAT);
414
415         while (proc) {
416
417                 if (i2c_hdmi_phy_context.state != STATE_RX_STOP) {
418
419                         if (s5p_hdmi_i2c_phy_interruptwait() != 0) {
420                                 tvout_err("interrupt wait failed!!!\n");
421                                 ret = -1;
422                                 break;
423                         }
424
425                 }
426
427                 switch (i2c_hdmi_phy_context.state) {
428                 case STATE_RX_DATA:
429                         reg = readb(i2c_hdmi_phy_base + HDMI_I2C_DS);
430                         *(i2c_hdmi_phy_context.buffer) = reg;
431
432                         i2c_hdmi_phy_context.buffer++;
433                         --(i2c_hdmi_phy_context.bytes);
434
435                         if (i2c_hdmi_phy_context.bytes == 1) {
436                                 i2c_hdmi_phy_context.state = STATE_RX_STOP;
437                                 writeb(I2C_CLK_PEND_INT,
438                                         i2c_hdmi_phy_base + HDMI_I2C_CON);
439                         } else {
440                                 writeb(I2C_CLK_PEND_INT | I2C_ACK,
441                                         i2c_hdmi_phy_base + HDMI_I2C_CON);
442                         }
443
444                         break;
445
446                 case STATE_RX_ADDR:
447                         i2c_hdmi_phy_context.state = STATE_RX_DATA;
448
449                         if (i2c_hdmi_phy_context.bytes == 1) {
450                                 i2c_hdmi_phy_context.state = STATE_RX_STOP;
451                                 writeb(I2C_CLK_PEND_INT,
452                                         i2c_hdmi_phy_base + HDMI_I2C_CON);
453                         } else {
454                                 writeb(I2C_CLK_PEND_INT | I2C_ACK,
455                                         i2c_hdmi_phy_base + HDMI_I2C_CON);
456                         }
457
458                         break;
459
460                 case STATE_RX_STOP:
461                         i2c_hdmi_phy_context.state = STATE_IDLE;
462
463                         reg = readb(i2c_hdmi_phy_base + HDMI_I2C_DS);
464
465                         *(i2c_hdmi_phy_context.buffer) = reg;
466
467                         writeb(I2C_MODE_MRX|I2C_ENABLE,
468                                 i2c_hdmi_phy_base + HDMI_I2C_STAT);
469                         writeb(I2C_CLK_PEND_INT,
470                                 i2c_hdmi_phy_base + HDMI_I2C_CON);
471                         writeb(I2C_MODE_MRX,
472                                 i2c_hdmi_phy_base + HDMI_I2C_STAT);
473
474                         while (readb(i2c_hdmi_phy_base + HDMI_I2C_STAT) &
475                                         I2C_START)
476                                 msleep(1);
477
478                         proc = false;
479                         break;
480
481                 case STATE_IDLE:
482                 default:
483                         tvout_err("error state!!!\n");
484
485                         ret = -1;
486
487                         proc = false;
488                         break;
489                 }
490
491         }
492
493         return ret;
494 }
495
496 static s32 s5p_hdmi_i2c_phy_write(u8 addr, u8 nbytes, u8 *buffer)
497 {
498         u8 reg;
499         s32 ret = 0;
500         u32 proc = true;
501
502         i2c_hdmi_phy_context.state = STATE_TX_ADDR;
503         i2c_hdmi_phy_context.buffer = buffer;
504         i2c_hdmi_phy_context.bytes = nbytes;
505
506         writeb(I2C_CLK | I2C_INT | I2C_ACK, i2c_hdmi_phy_base + HDMI_I2C_CON);
507         writeb(I2C_ENABLE | I2C_MODE_MTX, i2c_hdmi_phy_base + HDMI_I2C_STAT);
508         writeb(addr & 0xFE, i2c_hdmi_phy_base + HDMI_I2C_DS);
509         writeb(I2C_ENABLE | I2C_START | I2C_MODE_MTX,
510                                 i2c_hdmi_phy_base + HDMI_I2C_STAT);
511
512         while (proc) {
513
514                 if (s5p_hdmi_i2c_phy_interruptwait() != 0) {
515                         tvout_err("interrupt wait failed!!!\n");
516                         ret = -1;
517
518                         break;
519                 }
520
521                 switch (i2c_hdmi_phy_context.state) {
522                 case STATE_TX_ADDR:
523                 case STATE_TX_DATA:
524                         i2c_hdmi_phy_context.state = STATE_TX_DATA;
525
526                         reg = *(i2c_hdmi_phy_context.buffer);
527
528                         writeb(reg, i2c_hdmi_phy_base + HDMI_I2C_DS);
529
530                         i2c_hdmi_phy_context.buffer++;
531                         --(i2c_hdmi_phy_context.bytes);
532
533                         if (i2c_hdmi_phy_context.bytes == 0) {
534                                 i2c_hdmi_phy_context.state = STATE_TX_STOP;
535                                 writeb(I2C_CLK_PEND_INT,
536                                         i2c_hdmi_phy_base + HDMI_I2C_CON);
537                         } else {
538                                 writeb(I2C_CLK_PEND_INT | I2C_ACK,
539                                         i2c_hdmi_phy_base + HDMI_I2C_CON);
540                         }
541
542                         break;
543
544                 case STATE_TX_STOP:
545                         i2c_hdmi_phy_context.state = STATE_IDLE;
546
547                         writeb(I2C_MODE_MTX | I2C_ENABLE,
548                                 i2c_hdmi_phy_base + HDMI_I2C_STAT);
549                         writeb(I2C_CLK_PEND_INT,
550                                 i2c_hdmi_phy_base + HDMI_I2C_CON);
551                         writeb(I2C_MODE_MTX,
552                                 i2c_hdmi_phy_base + HDMI_I2C_STAT);
553
554                         while (readb(i2c_hdmi_phy_base + HDMI_I2C_STAT) &
555                                         I2C_START)
556                                 msleep(1);
557
558                         proc = false;
559                         break;
560
561                 case STATE_IDLE:
562                 default:
563                         tvout_err("error state!!!\n");
564
565                         ret = -1;
566
567                         proc = false;
568                         break;
569                 }
570
571         }
572
573         return ret;
574 }
575
576 #ifdef CONFIG_SND_S5P_SPDIF
577 static void s5p_hdmi_audio_set_config(
578                 enum s5p_tvout_audio_codec_type audio_codec)
579 {
580         u32 data_type = (audio_codec == PCM) ?
581                         S5P_HDMI_SPDIFIN_CFG_LINEAR_PCM_TYPE :
582                         (audio_codec == AC3) ?
583                                 S5P_HDMI_SPDIFIN_CFG_NO_LINEAR_PCM_TYPE : 0xff;
584
585         tvout_dbg("audio codec type = %s\n",
586                 (audio_codec & PCM) ? "PCM" :
587                 (audio_codec & AC3) ? "AC3" :
588                 (audio_codec & MP3) ? "MP3" :
589                 (audio_codec & WMA) ? "WMA" : "Unknown");
590
591         /* open SPDIF path on HDMI_I2S */
592         writeb(S5P_HDMI_I2S_CLK_EN, hdmi_base + S5P_HDMI_I2S_CLK_CON);
593         writeb(readl(hdmi_base + S5P_HDMI_I2S_MUX_CON) |
594                 S5P_HDMI_I2S_CUV_I2S_ENABLE |
595                 S5P_HDMI_I2S_MUX_ENABLE,
596                 hdmi_base + S5P_HDMI_I2S_MUX_CON);
597         writeb(S5P_HDMI_I2S_CH_ALL_EN, hdmi_base + S5P_HDMI_I2S_MUX_CH);
598         writeb(S5P_HDMI_I2S_CUV_RL_EN, hdmi_base + S5P_HDMI_I2S_MUX_CUV);
599
600         writeb(S5P_HDMI_SPDIFIN_CFG_FILTER_2_SAMPLE | data_type |
601                 S5P_HDMI_SPDIFIN_CFG_PCPD_MANUAL_SET |
602                 S5P_HDMI_SPDIFIN_CFG_WORD_LENGTH_M_SET |
603                 S5P_HDMI_SPDIFIN_CFG_U_V_C_P_REPORT |
604                 S5P_HDMI_SPDIFIN_CFG_BURST_SIZE_2 |
605                 S5P_HDMI_SPDIFIN_CFG_DATA_ALIGN_32BIT,
606                 hdmi_base + S5P_HDMI_SPDIFIN_CONFIG_1);
607
608         writeb(S5P_HDMI_SPDIFIN_CFG2_NO_CLK_DIV,
609                 hdmi_base + S5P_HDMI_SPDIFIN_CONFIG_2);
610 }
611
612 static void s5p_hdmi_audio_clock_enable(void)
613 {
614         writeb(S5P_HDMI_SPDIFIN_CLK_ON, hdmi_base + S5P_HDMI_SPDIFIN_CLK_CTRL);
615         writeb(S5P_HDMI_SPDIFIN_STATUS_CHK_OP_MODE,
616                 hdmi_base + S5P_HDMI_SPDIFIN_OP_CTRL);
617 }
618
619 static void s5p_hdmi_audio_set_repetition_time(
620                                 enum s5p_tvout_audio_codec_type audio_codec,
621                                 u32 bits, u32 frame_size_code)
622 {
623         /* Only 4'b1011 24bit */
624         u32 wl = 5 << 1 | 1;
625         u32 rpt_cnt = (audio_codec == AC3) ? 1536 * 2 - 1 : 0;
626
627         tvout_dbg("repetition count = %d\n", rpt_cnt);
628
629         /* 24bit and manual mode */
630         writeb(((rpt_cnt & 0xf) << 4) | wl,
631                 hdmi_base + S5P_HDMI_SPDIFIN_USER_VALUE_1);
632         /* if PCM this value is 0 */
633         writeb((rpt_cnt >> 4) & 0xff,
634                 hdmi_base + S5P_HDMI_SPDIFIN_USER_VALUE_2);
635         /* if PCM this value is 0 */
636         writeb(frame_size_code & 0xff,
637                 hdmi_base + S5P_HDMI_SPDIFIN_USER_VALUE_3);
638         /* if PCM this value is 0 */
639         writeb((frame_size_code >> 8) & 0xff,
640                 hdmi_base + S5P_HDMI_SPDIFIN_USER_VALUE_4);
641 }
642
643 static void s5p_hdmi_audio_irq_enable(u32 irq_en)
644 {
645         writeb(irq_en, hdmi_base + S5P_HDMI_SPDIFIN_IRQ_MASK);
646 }
647 #else
648 static void s5p_hdmi_audio_i2s_config(
649                 enum s5p_tvout_audio_codec_type audio_codec,
650                 u32 sample_rate, u32 bits_per_sample,
651                 u32 frame_size_code)
652 {
653         u32 data_num, bit_ch, sample_frq;
654
655         if (bits_per_sample == 20) {
656                 data_num = 2;
657                 bit_ch  = 1;
658         } else if (bits_per_sample == 24) {
659                 data_num = 3;
660                 bit_ch  = 1;
661         } else {
662                 data_num = 1;
663                 bit_ch  = 0;
664         }
665
666         writeb((S5P_HDMI_I2S_IN_DISABLE | S5P_HDMI_I2S_AUD_I2S |
667                 S5P_HDMI_I2S_CUV_I2S_ENABLE | S5P_HDMI_I2S_MUX_ENABLE),
668                 hdmi_base + S5P_HDMI_I2S_MUX_CON);
669
670         writeb(S5P_HDMI_I2S_CH0_EN | S5P_HDMI_I2S_CH1_EN | S5P_HDMI_I2S_CH2_EN,
671                 hdmi_base + S5P_HDMI_I2S_MUX_CH);
672
673         writeb(S5P_HDMI_I2S_CUV_RL_EN, hdmi_base + S5P_HDMI_I2S_MUX_CUV);
674
675         sample_frq = (sample_rate == 44100) ? 0 :
676                         (sample_rate == 48000) ? 2 :
677                         (sample_rate == 32000) ? 3 :
678                         (sample_rate == 96000) ? 0xa : 0x0;
679
680         /* readl(hdmi_base + S5P_HDMI_YMAX) */
681         writeb(S5P_HDMI_I2S_CLK_DIS, hdmi_base + S5P_HDMI_I2S_CLK_CON);
682         writeb(S5P_HDMI_I2S_CLK_EN, hdmi_base + S5P_HDMI_I2S_CLK_CON);
683
684         writeb(readl(hdmi_base + S5P_HDMI_I2S_DSD_CON) | 0x01,
685                 hdmi_base + S5P_HDMI_I2S_DSD_CON);
686
687         /* Configuration I2S input ports. Configure I2S_PIN_SEL_0~4 */
688         writeb(S5P_HDMI_I2S_SEL_SCLK(5) | S5P_HDMI_I2S_SEL_LRCK(6),
689                 hdmi_base + S5P_HDMI_I2S_PIN_SEL_0);
690         writeb(S5P_HDMI_I2S_SEL_SDATA1(1) | S5P_HDMI_I2S_SEL_SDATA2(4),
691                 hdmi_base + S5P_HDMI_I2S_PIN_SEL_1);
692         writeb(S5P_HDMI_I2S_SEL_SDATA3(1) | S5P_HDMI_I2S_SEL_SDATA2(2),
693                 hdmi_base + S5P_HDMI_I2S_PIN_SEL_2);
694         writeb(S5P_HDMI_I2S_SEL_DSD(0), hdmi_base + S5P_HDMI_I2S_PIN_SEL_3);
695
696         /* I2S_CON_1 & 2 */
697         writeb(S5P_HDMI_I2S_SCLK_RISING_EDGE | S5P_HDMI_I2S_L_CH_LOW_POL,
698                 hdmi_base + S5P_HDMI_I2S_CON_1);
699         writeb(S5P_HDMI_I2S_MSB_FIRST_MODE |
700                 S5P_HDMI_I2S_SET_BIT_CH(bit_ch) |
701                 S5P_HDMI_I2S_SET_SDATA_BIT(data_num) |
702                 S5P_HDMI_I2S_BASIC_FORMAT,
703                 hdmi_base + S5P_HDMI_I2S_CON_2);
704
705         /* Configure register related to CUV information */
706         writeb(S5P_HDMI_I2S_CH_STATUS_MODE_0 |
707                 S5P_HDMI_I2S_2AUD_CH_WITHOUT_PREEMPH |
708                 S5P_HDMI_I2S_COPYRIGHT |
709                 S5P_HDMI_I2S_LINEAR_PCM |
710                 S5P_HDMI_I2S_CONSUMER_FORMAT,
711                 hdmi_base + S5P_HDMI_I2S_CH_ST_0);
712         writeb(S5P_HDMI_I2S_CD_PLAYER,
713                 hdmi_base + S5P_HDMI_I2S_CH_ST_1);
714         writeb(S5P_HDMI_I2S_SET_SOURCE_NUM(0),
715                 hdmi_base + S5P_HDMI_I2S_CH_ST_2);
716         writeb(S5P_HDMI_I2S_CLK_ACCUR_LEVEL_2 |
717                 S5P_HDMI_I2S_SET_SAMPLING_FREQ(sample_frq),
718                 hdmi_base + S5P_HDMI_I2S_CH_ST_3);
719         writeb(S5P_HDMI_I2S_ORG_SAMPLING_FREQ_44_1 |
720                 S5P_HDMI_I2S_WORD_LENGTH_MAX24_24BITS |
721                 S5P_HDMI_I2S_WORD_LENGTH_MAX_24BITS,
722                 hdmi_base + S5P_HDMI_I2S_CH_ST_4);
723
724         writeb(S5P_HDMI_I2S_CH_STATUS_RELOAD,
725                 hdmi_base + S5P_HDMI_I2S_CH_ST_CON);
726 }
727 #endif
728
729 static u8 s5p_hdmi_checksum(int sum, int size, u8 *data)
730 {
731         u32 i;
732
733         for (i = 0; i < size; i++)
734                 sum += (u32)(data[i]);
735
736         return (u8)(0x100 - (sum & 0xff));
737 }
738
739
740 static int s5p_hdmi_phy_control(bool on, u8 addr, u8 offset, u8 *read_buffer)
741 {
742         u8 buff[2] = {0};
743
744         buff[0] = addr;
745         buff[1] = (on) ? (read_buffer[addr] & (~(1 << offset))) :
746                         (read_buffer[addr] | (1 << offset));
747
748         if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buff) != 0)
749                 return EINVAL;
750
751         return 0;
752 }
753
754 static bool s5p_hdmi_phy_is_enable(void)
755 {
756         u32 reg;
757
758 #ifdef CONFIG_CPU_S5PV310
759         reg = readl(S5PV310_VA_PMU + 0x0700);
760 #endif
761
762 #ifdef CONFIG_CPU_S5PV210
763         reg = readl(S3C_VA_SYS + 0xE804);
764 #endif
765
766         return reg & (1 << 0);
767 }
768
769 static void s5p_hdmi_phy_enable(bool on)
770 {
771         u32 reg;
772
773 #ifdef CONFIG_CPU_S5PV310
774         reg = readl(S5PV310_VA_PMU + 0x0700);
775
776         if (on)
777                 reg |= (1 << 0);
778         else
779                 reg &= ~(1 << 0);
780
781         writeb(reg, S5PV310_VA_PMU + 0x0700);
782 #endif
783
784 #ifdef CONFIG_CPU_S5PV210
785         reg = readl(S3C_VA_SYS + 0xE804);
786
787         if (on)
788                 reg |= (1 << 0);
789         else
790                 reg &= ~(1 << 0);
791
792         writeb(reg, S3C_VA_SYS + 0xE804);
793 #endif
794 }
795
796 int s5p_hdmi_phy_power(bool on)
797 {
798         u32 size;
799         u8 *buffer;
800         u8 read_buffer[0x40] = {0, };
801
802         size = sizeof(phy_config[0][0])
803                 / sizeof(phy_config[0][0][0]);
804
805         buffer = (u8 *) phy_config[0][0];
806
807         if (on) {
808                 if (!s5p_hdmi_phy_is_enable()) {
809                         s5p_hdmi_phy_enable(1);
810
811                         if (s5p_hdmi_i2c_phy_write(
812                                 PHY_I2C_ADDRESS, 1, buffer) != 0)
813                                 goto ret_on_err;
814
815                         if (s5p_hdmi_i2c_phy_read(
816                                 PHY_I2C_ADDRESS, size, read_buffer) != 0) {
817                                 tvout_err("s5p_hdmi_i2c_phy_read failed.\n");
818                                 goto ret_on_err;
819                         }
820
821                         s5p_hdmi_phy_control(true, 0x1, 0x5, read_buffer);
822                         s5p_hdmi_phy_control(true, 0x1, 0x7, read_buffer);
823                         s5p_hdmi_phy_control(true, 0x5, 0x5, read_buffer);
824                         s5p_hdmi_phy_control(true, 0x17, 0x0, read_buffer);
825                         s5p_hdmi_phy_control(true, 0x17, 0x1, read_buffer);
826                 }
827         } else {
828                 if (s5p_hdmi_phy_is_enable()) {
829                         if (s5p_hdmi_i2c_phy_write(
830                                 PHY_I2C_ADDRESS, 1, buffer) != 0)
831                                 goto ret_on_err;
832
833                         if (s5p_hdmi_i2c_phy_read(
834                                 PHY_I2C_ADDRESS, size, read_buffer) != 0) {
835                                 tvout_err("s5p_hdmi_i2c_phy_read failed.\n");
836                                 goto ret_on_err;
837                         }
838
839                         s5p_hdmi_phy_control(false, 0x1, 0x5, read_buffer);
840                         s5p_hdmi_phy_control(false, 0x1, 0x7, read_buffer);
841                         s5p_hdmi_phy_control(false, 0x5, 0x5, read_buffer);
842                         s5p_hdmi_phy_control(false, 0x17, 0x0, read_buffer);
843                         s5p_hdmi_phy_control(false, 0x17, 0x1, read_buffer);
844
845                         s5p_hdmi_phy_enable(0);
846                 }
847         }
848
849         return 0;
850
851 ret_on_err:
852         return -1;
853 }
854
855 s32 s5p_hdmi_phy_config(
856                 enum phy_freq freq, enum s5p_hdmi_color_depth cd)
857 {
858         s32 index;
859         s32 size;
860         u8 buffer[32] = {0, };
861         u8 reg;
862
863         switch (cd) {
864         case HDMI_CD_24:
865                 index = 0;
866                 break;
867
868         case HDMI_CD_30:
869                 index = 1;
870                 break;
871
872         case HDMI_CD_36:
873                 index = 2;
874                 break;
875
876         default:
877                 return -1;
878         }
879
880         buffer[0] = PHY_REG_MODE_SET_DONE;
881         buffer[1] = 0x00;
882
883         if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 2, buffer) != 0) {
884                 tvout_err("s5p_hdmi_i2c_phy_write failed.\n");
885                 return -1;
886         }
887
888         writeb(0x5, i2c_hdmi_phy_base + HDMI_I2C_LC);
889
890         size = sizeof(phy_config[freq][index])
891                 / sizeof(phy_config[freq][index][0]);
892
893         memcpy(buffer, phy_config[freq][index], sizeof(buffer));
894
895         if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, size, buffer) != 0)
896                 return -1;
897
898         buffer[0] = 0x01;
899
900         if (s5p_hdmi_i2c_phy_write(PHY_I2C_ADDRESS, 1, buffer) != 0) {
901                 tvout_err("s5p_hdmi_i2c_phy_write failed.\n");
902                 return -1;
903         }
904
905 #ifdef S5P_HDMI_DEBUG
906 {
907         int i = 0;
908         u8 read_buffer[0x40] = {0, };
909
910         /* read data */
911         if (s5p_hdmi_i2c_phy_read(PHY_I2C_ADDRESS, size, read_buffer) != 0) {
912                 tvout_err("s5p_hdmi_i2c_phy_read failed.\n");
913                 return -1;
914         }
915
916         tvout_dbg("read buffer :\n\t\t");
917
918         for (i = 1; i < size; i++) {
919                 printk("0x%02x", read_buffer[i]);
920
921                 if (i % 8)
922                         printk(" ");
923                 else
924                         printk("\n\t\t");
925         }
926         printk("\n");
927 }
928 #endif
929         s5p_hdmi_reg_core_reset();
930
931         do {
932                 reg = readb(hdmi_base + S5P_HDMI_PHY_STATUS);
933         } while (!(reg & S5P_HDMI_PHY_STATUS_READY));
934
935         writeb(I2C_CLK_PEND_INT, i2c_hdmi_phy_base + HDMI_I2C_CON);
936         writeb(I2C_IDLE, i2c_hdmi_phy_base + HDMI_I2C_STAT);
937
938         return 0;
939 }
940
941
942
943 void s5p_hdmi_set_gcp(enum s5p_hdmi_color_depth depth, u8 *gcp)
944 {
945         switch (depth) {
946         case HDMI_CD_48:
947                 gcp[1] = S5P_HDMI_GCP_48BPP; break;
948         case HDMI_CD_36:
949                 gcp[1] = S5P_HDMI_GCP_36BPP; break;
950         case HDMI_CD_30:
951                 gcp[1] = S5P_HDMI_GCP_30BPP; break;
952         case HDMI_CD_24:
953                 gcp[1] = S5P_HDMI_GCP_24BPP; break;
954
955         default:
956                 break;
957         }
958 }
959
960 void s5p_hdmi_reg_acr(u8 *acr)
961 {
962         u32 n   = acr[4] << 16 | acr[5] << 8 | acr[6];
963         u32 cts = acr[1] << 16 | acr[2] << 8 | acr[3];
964
965         hdmi_write_24(n, hdmi_base + S5P_HDMI_ACR_N0);
966         hdmi_write_24(cts, hdmi_base + S5P_HDMI_ACR_MCTS0);
967         hdmi_write_24(cts, hdmi_base + S5P_HDMI_ACR_CTS0);
968
969         writeb(4, hdmi_base + S5P_HDMI_ACR_CON);
970 }
971
972 void s5p_hdmi_reg_asp(u8 *asp)
973 {
974         writeb(S5P_HDMI_AUD_NO_DST_DOUBLE | S5P_HDMI_AUD_TYPE_SAMPLE |
975                 S5P_HDMI_AUD_MODE_TWO_CH | S5P_HDMI_AUD_SP_ALL_DIS,
976                 hdmi_base + S5P_HDMI_ASP_CON);
977
978         writeb(S5P_HDMI_ASP_SP_FLAT_AUD_SAMPLE,
979                 hdmi_base + S5P_HDMI_ASP_SP_FLAT);
980
981         writeb(S5P_HDMI_SPK0R_SEL_I_PCM0R | S5P_HDMI_SPK0L_SEL_I_PCM0L,
982                 hdmi_base + S5P_HDMI_ASP_CHCFG0);
983         writeb(S5P_HDMI_SPK0R_SEL_I_PCM0R | S5P_HDMI_SPK0L_SEL_I_PCM0L,
984                 hdmi_base + S5P_HDMI_ASP_CHCFG1);
985         writeb(S5P_HDMI_SPK0R_SEL_I_PCM0R | S5P_HDMI_SPK0L_SEL_I_PCM0L,
986                 hdmi_base + S5P_HDMI_ASP_CHCFG2);
987         writeb(S5P_HDMI_SPK0R_SEL_I_PCM0R | S5P_HDMI_SPK0L_SEL_I_PCM0L,
988                 hdmi_base + S5P_HDMI_ASP_CHCFG3);
989 }
990
991 void s5p_hdmi_reg_gcp(u8 i_p, u8 *gcp)
992 {
993         u32 gcp_con;
994
995         writeb(gcp[2], hdmi_base + S5P_HDMI_GCP_BYTE2);
996
997         gcp_con = readb(hdmi_base + S5P_HDMI_GCP_CON);
998
999         if (i_p)
1000                 gcp_con |= S5P_HDMI_GCP_CON_EN_1ST_VSYNC |
1001                                 S5P_HDMI_GCP_CON_EN_2ST_VSYNC;
1002         else
1003                 gcp_con &= (~(S5P_HDMI_GCP_CON_EN_1ST_VSYNC |
1004                                 S5P_HDMI_GCP_CON_EN_2ST_VSYNC));
1005
1006         writeb(gcp_con, hdmi_base + S5P_HDMI_GCP_CON);
1007
1008 }
1009
1010 void s5p_hdmi_reg_acp(u8 *header, u8 *acp)
1011 {
1012         writeb(header[1], hdmi_base + S5P_HDMI_ACP_TYPE);
1013 }
1014
1015 void s5p_hdmi_reg_isrc(u8 *isrc1, u8 *isrc2)
1016 {
1017 }
1018
1019 void s5p_hdmi_reg_gmp(u8 *gmp)
1020 {
1021 }
1022
1023 void s5p_hdmi_reg_infoframe(struct s5p_hdmi_infoframe *info, u8 *data)
1024 {
1025         u32 start_addr = 0, sum_addr = 0;
1026         u8 sum;
1027
1028         switch (info->type) {
1029         case HDMI_VSI_INFO:
1030                 break;
1031         case HDMI_AVI_INFO:
1032                 sum_addr        = S5P_HDMI_AVI_CHECK_SUM;
1033                 start_addr      = S5P_HDMI_AVI_DATA;
1034                 break;
1035         case HDMI_SPD_INFO:
1036                 sum_addr        = S5P_HDMI_SPD_DATA;
1037                 start_addr      = S5P_HDMI_SPD_DATA + 4;
1038                 /* write header */
1039                 writeb((u8)info->type, hdmi_base + S5P_HDMI_SPD_HEADER);
1040                 writeb((u8)info->version, hdmi_base + S5P_HDMI_SPD_HEADER + 4);
1041                 writeb((u8)info->length, hdmi_base + S5P_HDMI_SPD_HEADER + 8);
1042                 break;
1043         case HDMI_AUI_INFO:
1044                 sum_addr        = S5P_HDMI_AUI_CHECK_SUM;
1045                 start_addr      = S5P_HDMI_AUI_BYTE1;
1046                 break;
1047         case HDMI_MPG_INFO:
1048                 sum_addr        = S5P_HDMI_MPG_CHECK_SUM;
1049                 start_addr      = S5P_HDMI_MPG_DATA;
1050                 break;
1051         default:
1052                 tvout_dbg("undefined infoframe\n");
1053                 return;
1054         }
1055
1056         /* calculate checksum */
1057         sum = (u8)info->type + info->version + info->length;
1058         sum = s5p_hdmi_checksum(sum, info->length, data);
1059
1060         /* write checksum */
1061         writeb(sum, hdmi_base + sum_addr);
1062
1063         /* write data */
1064         hdmi_write_l(data, hdmi_base, start_addr, info->length);
1065 }
1066
1067 void s5p_hdmi_reg_tg(struct s5p_hdmi_v_frame *frame)
1068 {
1069         u16 reg;
1070         u8 tg;
1071
1072         hdmi_write_16(frame->h_total, hdmi_base + S5P_HDMI_TG_H_FSZ_L);
1073         hdmi_write_16(frame->h_blank, hdmi_base + S5P_HDMI_TG_HACT_ST_L);
1074         hdmi_write_16(frame->h_active, hdmi_base + S5P_HDMI_TG_HACT_SZ_L);
1075
1076         hdmi_write_16(frame->v_total, hdmi_base + S5P_HDMI_TG_V_FSZ_L);
1077         hdmi_write_16(frame->v_active, hdmi_base + S5P_HDMI_TG_VACT_SZ_L);
1078
1079
1080         reg = (frame->i_p) ? (frame->v_total - frame->v_active*2) / 2 :
1081                                 frame->v_total - frame->v_active;
1082         hdmi_write_16(reg, hdmi_base + S5P_HDMI_TG_VACT_ST_L);
1083
1084         reg = (frame->i_p) ? 0x249 : 0x248;
1085         hdmi_write_16(reg, hdmi_base + S5P_HDMI_TG_VACT_ST2_L);
1086
1087         reg = (frame->i_p) ? 0x233 : 1;
1088         hdmi_write_16(reg, hdmi_base + S5P_HDMI_TG_VSYNC_BOT_HDMI_L);
1089
1090         /* write reg default value */
1091         hdmi_write_16(0x1, hdmi_base + S5P_HDMI_TG_VSYNC_L);
1092         hdmi_write_16(0x233, hdmi_base + S5P_HDMI_TG_VSYNC2_L);
1093         hdmi_write_16(0x233, hdmi_base + S5P_HDMI_TG_FIELD_CHG_L);
1094         hdmi_write_16(0x1, hdmi_base + S5P_HDMI_TG_VSYNC_TOP_HDMI_L);
1095         hdmi_write_16(0x1, hdmi_base + S5P_HDMI_TG_FIELD_TOP_HDMI_L);
1096         hdmi_write_16(0x233, hdmi_base + S5P_HDMI_TG_FIELD_BOT_HDMI_L);
1097
1098         tg = readb(hdmi_base + S5P_HDMI_TG_CMD);
1099
1100         hdmi_bit_set(frame->i_p, tg, S5P_HDMI_FIELD);
1101
1102         writeb(tg, hdmi_base + S5P_HDMI_TG_CMD);
1103 }
1104
1105 void s5p_hdmi_reg_v_timing(struct s5p_hdmi_v_format *v)
1106 {
1107         u32 reg32;
1108
1109         struct s5p_hdmi_v_frame *frame = &(v->frame);
1110
1111         writeb(frame->polarity, hdmi_base + S5P_HDMI_SYNC_MODE);
1112         writeb(frame->i_p, hdmi_base + S5P_HDMI_INT_PRO_MODE);
1113
1114         hdmi_write_16(frame->h_blank, hdmi_base + S5P_HDMI_H_BLANK_0);
1115
1116         reg32 = (frame->v_blank << 11) | (frame->v_blank + frame->v_active);
1117         hdmi_write_24(reg32, hdmi_base + S5P_HDMI_V_BLANK_0);
1118
1119         reg32 = (frame->h_total << 12) | frame->v_total;
1120         hdmi_write_24(reg32, hdmi_base + S5P_HDMI_H_V_LINE_0);
1121
1122         reg32 = frame->polarity << 20 | v->h_sync.end << 10 | v->h_sync.begin;
1123         hdmi_write_24(reg32, hdmi_base + S5P_HDMI_H_SYNC_GEN_0);
1124
1125         reg32 = v->v_sync_top.begin << 12 | v->v_sync_top.end;
1126         hdmi_write_24(reg32, hdmi_base + S5P_HDMI_V_SYNC_GEN_1_0);
1127
1128         if (frame->i_p) {
1129                 reg32 = v->v_blank_f.end << 11 | v->v_blank_f.begin;
1130                 hdmi_write_24(reg32, hdmi_base + S5P_HDMI_V_BLANK_F_0);
1131
1132                 reg32 = v->v_sync_bottom.begin << 12 | v->v_sync_bottom.end;
1133                 hdmi_write_24(reg32, hdmi_base + S5P_HDMI_V_SYNC_GEN_2_0);
1134
1135                 reg32 = v->v_sync_h_pos.begin << 12 | v->v_sync_h_pos.end;
1136                 hdmi_write_24(reg32, hdmi_base + S5P_HDMI_V_SYNC_GEN_3_0);
1137         } else {
1138                 hdmi_write_24(0x0, hdmi_base + S5P_HDMI_V_BLANK_F_0);
1139                 hdmi_write_24(0x1001, hdmi_base + S5P_HDMI_V_SYNC_GEN_2_0);
1140                 hdmi_write_24(0x1001, hdmi_base + S5P_HDMI_V_SYNC_GEN_3_0);
1141         }
1142 }
1143
1144 void s5p_hdmi_reg_bluescreen_clr(u8 cb_b, u8 y_g, u8 cr_r)
1145 {
1146         writeb(cb_b, hdmi_base + S5P_HDMI_BLUE_SCREEN_0);
1147         writeb(y_g, hdmi_base + S5P_HDMI_BLUE_SCREEN_1);
1148         writeb(cr_r, hdmi_base + S5P_HDMI_BLUE_SCREEN_2);
1149 }
1150
1151 void s5p_hdmi_reg_bluescreen(bool en)
1152 {
1153         u8 reg = readl(hdmi_base + S5P_HDMI_CON_0);
1154
1155         hdmi_bit_set(en, reg, S5P_HDMI_BLUE_SCR_EN);
1156
1157         writeb(reg, hdmi_base + S5P_HDMI_CON_0);
1158 }
1159
1160 void s5p_hdmi_reg_clr_range(u8 y_min, u8 y_max, u8 c_min, u8 c_max)
1161 {
1162         writeb(y_max, hdmi_base + S5P_HDMI_YMAX);
1163         writeb(y_min, hdmi_base + S5P_HDMI_YMIN);
1164         writeb(c_max, hdmi_base + S5P_HDMI_CMAX);
1165         writeb(c_min, hdmi_base + S5P_HDMI_CMIN);
1166 }
1167
1168 void s5p_hdmi_reg_tg_cmd(bool time, bool bt656, bool tg)
1169 {
1170         u8 reg = 0;
1171
1172         reg = readb(hdmi_base + S5P_HDMI_TG_CMD);
1173
1174         hdmi_bit_set(time, reg, S5P_HDMI_GETSYNC_TYPE);
1175         hdmi_bit_set(bt656, reg, S5P_HDMI_GETSYNC);
1176         hdmi_bit_set(tg, reg, S5P_HDMI_TG);
1177
1178         writeb(reg, hdmi_base + S5P_HDMI_TG_CMD);
1179 }
1180
1181 void s5p_hdmi_reg_enable(bool en)
1182 {
1183         u8 reg;
1184
1185         reg = readl(hdmi_base + S5P_HDMI_CON_0);
1186
1187         if (en)
1188                 reg |= S5P_HDMI_EN;
1189         else
1190                 reg &= ~(S5P_HDMI_EN | S5P_HDMI_ASP_EN);
1191
1192         writeb(reg, hdmi_base + S5P_HDMI_CON_0);
1193 }
1194
1195 u8 s5p_hdmi_reg_intc_status(void)
1196 {
1197         return readb(hdmi_base + S5P_HDMI_INTC_FLAG);
1198 }
1199
1200 u8 s5p_hdmi_reg_intc_get_enabled(void)
1201 {
1202         return readb(hdmi_base + S5P_HDMI_INTC_CON);
1203 }
1204
1205 void s5p_hdmi_reg_intc_clear_pending(enum s5p_hdmi_interrrupt intr)
1206 {
1207         u8 reg;
1208
1209         reg = readb(hdmi_base + S5P_HDMI_INTC_FLAG);
1210         writeb(reg | (1 << intr), hdmi_base + S5P_HDMI_INTC_FLAG);
1211 }
1212
1213
1214 void s5p_hdmi_reg_sw_hpd_enable(bool enable)
1215 {
1216         u8 reg;
1217
1218         reg = readb(hdmi_base + S5P_HDMI_HPD);
1219         reg &= ~S5P_HDMI_HPD_SEL_I_HPD;
1220
1221         if (enable)
1222                 writeb(reg | S5P_HDMI_HPD_SEL_I_HPD, hdmi_base + S5P_HDMI_HPD);
1223         else
1224                 writeb(reg, hdmi_base + S5P_HDMI_HPD);
1225 }
1226
1227 void s5p_hdmi_reg_set_hpd_onoff(bool on_off)
1228 {
1229         u8 reg;
1230
1231         reg = readb(hdmi_base + S5P_HDMI_HPD);
1232         reg &= ~S5P_HDMI_SW_HPD_PLUGGED;
1233
1234         if (on_off)
1235                 writel(reg | S5P_HDMI_SW_HPD_PLUGGED,
1236                         hdmi_base + S5P_HDMI_HPD);
1237         else
1238                 writel(reg | S5P_HDMI_SW_HPD_UNPLUGGED,
1239                         hdmi_base + S5P_HDMI_HPD);
1240
1241 }
1242
1243 u8 s5p_hdmi_reg_get_hpd_status(void)
1244 {
1245         return readb(hdmi_base + S5P_HDMI_HPD_STATUS);
1246 }
1247
1248 void s5p_hdmi_reg_hpd_gen(void)
1249 {
1250         writeb(0xFF, hdmi_base + S5P_HDMI_HPD_GEN);
1251 }
1252
1253 int s5p_hdmi_reg_intc_set_isr(irqreturn_t (*isr)(int, void *), u8 num)
1254 {
1255         if (!isr) {
1256                 tvout_err("invalid irq routine\n");
1257                 return -1;
1258         }
1259
1260         if (num > HDMI_IRQ_TOTAL_NUM) {
1261                 tvout_err("max irq_num exceeded\n");
1262                 return -1;
1263         }
1264
1265         if (s5p_hdmi_isr_ftn[num])
1266                 tvout_dbg("irq %d already registered\n", num);
1267
1268         s5p_hdmi_isr_ftn[num] = isr;
1269
1270         tvout_dbg("success to register irq : %d\n", num);
1271
1272         return 0;
1273 }
1274
1275 void s5p_hdmi_reg_intc_enable(enum s5p_hdmi_interrrupt intr, u8 en)
1276 {
1277         u8 reg;
1278
1279         reg = s5p_hdmi_reg_intc_get_enabled();
1280
1281         if (en) {
1282                 if (!reg)
1283                         reg |= S5P_HDMI_INTC_EN_GLOBAL;
1284
1285                 reg |= (1 << intr);
1286         } else {
1287                 reg &= ~(1 << intr);
1288
1289                 if (!reg)
1290                         reg &= ~S5P_HDMI_INTC_EN_GLOBAL;
1291         }
1292
1293         writeb(reg, hdmi_base + S5P_HDMI_INTC_CON);
1294 }
1295
1296 void s5p_hdmi_reg_audio_enable(u8 en)
1297 {
1298         u8 con, mod;
1299         con = readb(hdmi_base + S5P_HDMI_CON_0);
1300         mod = readb(hdmi_base + S5P_HDMI_MODE_SEL);
1301
1302         if (en) {
1303                 if (mod & S5P_HDMI_DVI_MODE_EN)
1304                         return;
1305
1306                 con |= S5P_HDMI_ASP_EN;
1307                 writeb(HDMI_TRANS_EVERY_SYNC, hdmi_base + S5P_HDMI_AUI_CON);
1308         } else {
1309                 con &= ~S5P_HDMI_ASP_EN;
1310                 writeb(HDMI_DO_NOT_TANS, hdmi_base + S5P_HDMI_AUI_CON);
1311         }
1312
1313         writeb(con, hdmi_base + S5P_HDMI_CON_0);
1314 }
1315
1316 int s5p_hdmi_audio_init(
1317                 enum s5p_tvout_audio_codec_type audio_codec,
1318                 u32 sample_rate, u32 bits, u32 frame_size_code)
1319 {
1320 #ifdef CONFIG_SND_S5P_SPDIF
1321         s5p_hdmi_audio_set_config(audio_codec);
1322         s5p_hdmi_audio_set_repetition_time(audio_codec, bits, frame_size_code);
1323         s5p_hdmi_audio_irq_enable(S5P_HDMI_SPDIFIN_IRQ_OVERFLOW_EN);
1324         s5p_hdmi_audio_clock_enable();
1325 #else
1326         s5p_hdmi_audio_i2s_config(audio_codec, sample_rate, bits,
1327                                 frame_size_code);
1328 #endif
1329         return 0;
1330 }
1331
1332 void s5p_hdmi_reg_mute(bool en)
1333 {
1334         static u8 prev_audio;
1335         u8 reg;
1336
1337         s5p_hdmi_reg_bluescreen(en);
1338
1339         if (en) {
1340                 reg = readb(hdmi_base + S5P_HDMI_CON_0);
1341                 prev_audio = reg & S5P_HDMI_ASP_EN;
1342         } else
1343                 if (!prev_audio)
1344                         return;
1345
1346         s5p_hdmi_reg_audio_enable(!en);
1347 }
1348
1349 irqreturn_t s5p_hdmi_irq(int irq, void *dev_id)
1350 {
1351         u8 state, num = 0;
1352
1353         spin_lock_irq(&lock_hdmi);
1354
1355         state = readb(hdmi_base + S5P_HDMI_INTC_FLAG);
1356
1357         if (!state) {
1358                 tvout_err("undefined irq : %d\n", state);
1359                 goto irq_handled;
1360         }
1361
1362         for (num = 0; num < HDMI_IRQ_TOTAL_NUM; num++) {
1363
1364                 if (!(state & (1 << num)))
1365                         continue;
1366
1367                 if (s5p_hdmi_isr_ftn[num])
1368                         (s5p_hdmi_isr_ftn[num])(num, NULL);
1369                 else
1370                         tvout_dbg("unregistered irq : %d\n", num);
1371         }
1372
1373 irq_handled:
1374         spin_unlock_irq(&lock_hdmi);
1375
1376         return IRQ_HANDLED;
1377 }
1378
1379 void s5p_hdmi_init(void __iomem *hdmi_addr, void __iomem *hdmi_phy_addr)
1380 {
1381         hdmi_base = hdmi_addr;
1382         i2c_hdmi_phy_base = hdmi_phy_addr;
1383
1384         spin_lock_init(&lock_hdmi);
1385
1386         writeb(0x5, i2c_hdmi_phy_base + HDMI_I2C_LC);
1387 }
1388
1389 void s5p_hdmi_reg_output(struct s5p_hdmi_o_reg *reg)
1390 {
1391         writeb(reg->pxl_limit, hdmi_base + S5P_HDMI_CON_1);
1392         writeb(reg->preemble, hdmi_base + S5P_HDMI_CON_2);
1393         writeb(reg->mode, hdmi_base + S5P_HDMI_MODE_SEL);
1394 }
1395
1396 void s5p_hdmi_reg_packet_trans(struct s5p_hdmi_o_trans *trans)
1397 {
1398         u8 reg;
1399
1400         writeb(trans->avi, hdmi_base + S5P_HDMI_AVI_CON);
1401         writeb(trans->mpg, hdmi_base + S5P_HDMI_MPG_CON);
1402         writeb(trans->spd, hdmi_base + S5P_HDMI_SPD_CON);
1403         writeb(trans->gmp, hdmi_base + S5P_HDMI_GAMUT_CON);
1404         writeb(trans->aui, hdmi_base + S5P_HDMI_AUI_CON);
1405
1406         reg = trans->gcp | readb(hdmi_base + S5P_HDMI_GCP_CON);
1407         writeb(reg, hdmi_base + S5P_HDMI_GCP_CON);
1408
1409         reg = trans->isrc | readb(hdmi_base + S5P_HDMI_ISRC_CON);
1410         writeb(reg, hdmi_base + S5P_HDMI_ISRC_CON);
1411
1412         reg = trans->acp | readb(hdmi_base + S5P_HDMI_ACP_CON);
1413         writeb(reg, hdmi_base + S5P_HDMI_ACP_CON);
1414
1415         reg = trans->acr | readb(hdmi_base + S5P_HDMI_ACP_CON);
1416         writeb(reg, hdmi_base + S5P_HDMI_ACR_CON);
1417 }