1 /***************************************************************************
3 * Open \______ \ ____ ____ | | _\_ |__ _______ ___
4 * Source | _// _ \_/ ___\| |/ /| __ \ / _ \ \/ /
5 * Jukebox | | ( <_> ) \___| < | \_\ ( <_> > < <
6 * Firmware |____|_ /\____/ \___ >__|_ \|___ /\____/__/\_ \
10 * Copyright (C) 2011 by amaury Pouly
12 * Based on Rockbox iriver bootloader by Linus Nielsen Feltzing
13 * and the ipodlinux bootloader by Daniel Palffy and Bernard Leach
15 * This program is free software; you can redistribute it and/or
16 * modify it under the terms of the GNU General Public License
17 * as published by the Free Software Foundation; either version 2
18 * of the License, or (at your option) any later version.
20 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY
21 * KIND, either express or implied.
23 ****************************************************************************/
26 #include "dcp-imx233.h"
28 #include "kernel-imx233.h"
30 /* The hardware uses 160 bytes of storage to enable context switching */
31 static uint8_t dcp_context
[160] NOCACHEBSS_ATTR
;
33 static struct channel_arbiter_t channel_arbiter
;
35 static struct imx233_dcp_packet_t channel_packet
[HW_DCP_NUM_CHANNELS
];
36 /* completion semaphore */
37 static struct semaphore channel_sema
[HW_DCP_NUM_CHANNELS
];
41 /* clear interrupt and wakeup completion handler */
42 for(int i
= 0; i
< HW_DCP_NUM_CHANNELS
; i
++)
44 if(HW_DCP_STAT
& HW_DCP_STAT__IRQ(i
))
46 __REG_CLR(HW_DCP_STAT
) = HW_DCP_STAT__IRQ(i
);
47 semaphore_release(&channel_sema
[i
]);
52 void imx233_dcp_init(void)
55 imx233_reset_block(&HW_DCP_CTRL
);
56 /* Setup contexte pointer */
57 HW_DCP_CONTEXT
= (uint32_t)PHYSICAL_ADDR(&dcp_context
);
58 /* Enable context switching and caching */
59 __REG_SET(HW_DCP_CTRL
) = HW_DCP_CTRL__ENABLE_CONTEXT_CACHING
|
60 HW_DCP_CTRL__ENABLE_CONTEXT_SWITCHING
;
61 /* Check that there are sufficiently many channels */
62 if(__XTRACT(HW_DCP_CAPABILITY0
, NUM_CHANNELS
) != HW_DCP_NUM_CHANNELS
)
63 panicf("DCP has %lu channels but was configured to use %d !",
64 __XTRACT(HW_DCP_CAPABILITY0
, NUM_CHANNELS
), HW_DCP_NUM_CHANNELS
);
65 /* Setup channel arbiter to use */
66 arbiter_init(&channel_arbiter
, HW_DCP_NUM_CHANNELS
);
67 /* Merge channel0 interrupt */
68 __REG_SET(HW_DCP_CHANNELCTRL
) = HW_DCP_CHANNELCTRL__CH0_IRQ_MERGED
;
69 /* setup semaphores */
70 for(int i
= 0; i
< HW_DCP_NUM_CHANNELS
; i
++)
71 semaphore_init(&channel_sema
[i
], 1, 0);
74 // return OBJ_WAIT_TIMEOUT on failure
75 int imx233_dcp_acquire_channel(int timeout
)
77 return arbiter_acquire(&channel_arbiter
, timeout
);
80 void imx233_dcp_release_channel(int chan
)
82 arbiter_release(&channel_arbiter
, chan
);
85 // doesn't check that channel is in use!
86 void imx233_dcp_reserve_channel(int channel
)
88 arbiter_reserve(&channel_arbiter
, channel
);
91 static enum imx233_dcp_error_t
get_error_status(int ch
)
93 uint32_t stat
= channel_packet
[ch
].status
;
94 if(stat
& HW_DCP_STATUS__ERROR_SETUP
)
95 return DCP_ERROR_SETUP
;
96 if(stat
& HW_DCP_STATUS__ERROR_PACKET
)
97 return DCP_ERROR_PACKET
;
98 if(stat
& HW_DCP_STATUS__ERROR_SRC
)
100 if(stat
& HW_DCP_STATUS__ERROR_DST
)
101 return DCP_ERROR_DST
;
102 switch(__XTRACT_EX(stat
, HW_DCP_STATUS__ERROR_CODE
))
104 case 0: return DCP_SUCCESS
;
105 case 1: return DCP_ERROR_CHAIN_IS_0
;
106 case 2: return DCP_ERROR_NO_CHAIN
;
107 case 3: return DCP_ERROR_CONTEXT
;
108 case 4: return DCP_ERROR_PAYLOAD
;
109 case 5: return DCP_ERROR_MODE
;
110 default: return DCP_ERROR
;
114 static enum imx233_dcp_error_t
imx233_dcp_job(int ch
)
116 /* if IRQs are not enabled, don't enable channel interrupt and do some polling */
117 bool irq_enabled
= irq_enabled();
118 /* enable channel, clear interrupt, enable interrupt */
119 imx233_icoll_enable_interrupt(INT_SRC_DCP
, true);
121 __REG_SET(HW_DCP_CTRL
) = HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(ch
);
122 __REG_CLR(HW_DCP_STAT
) = HW_DCP_STAT__IRQ(ch
);
123 __REG_SET(HW_DCP_CHANNELCTRL
) = HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(ch
);
125 /* write back packet */
126 commit_discard_dcache_range(&channel_packet
[ch
], sizeof(struct imx233_dcp_packet_t
));
127 /* write 1 to semaphore to run job */
128 HW_DCP_CHxCMDPTR(ch
) = (uint32_t)PHYSICAL_ADDR(&channel_packet
[ch
]);
129 HW_DCP_CHxSEMA(ch
) = 1;
130 /* wait completion */
132 semaphore_wait(&channel_sema
[ch
], TIMEOUT_BLOCK
);
134 while(__XTRACT_EX(HW_DCP_CHxSEMA(ch
), HW_DCP_CHxSEMA__VALUE
))
136 /* disable channel and interrupt */
137 __REG_CLR(HW_DCP_CTRL
) = HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(ch
);
138 __REG_CLR(HW_DCP_CHANNELCTRL
) = HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(ch
);
140 return get_error_status(ch
);
144 enum imx233_dcp_error_t
imx233_dcp_memcpy_ex(int ch
, bool fill
, const void *src
, void *dst
, size_t len
)
147 channel_packet
[ch
].next
= 0;
148 channel_packet
[ch
].ctrl0
= HW_DCP_CTRL0__INTERRUPT_ENABLE
|
149 HW_DCP_CTRL0__ENABLE_MEMCOPY
| HW_DCP_CTRL0__DECR_SEMAPHORE
|
150 (fill
? HW_DCP_CTRL0__CONSTANT_FILL
: 0);
151 channel_packet
[ch
].ctrl1
= 0;
152 channel_packet
[ch
].src
= (uint32_t)(fill
? src
: PHYSICAL_ADDR(src
));
153 channel_packet
[ch
].dst
= (uint32_t)PHYSICAL_ADDR(dst
);
154 channel_packet
[ch
].size
= len
;
155 channel_packet
[ch
].payload
= 0;
156 channel_packet
[ch
].status
= 0;
158 /* write-back src if not filling, discard dst */
160 commit_discard_dcache_range(src
, len
);
161 discard_dcache_range(dst
, len
);
164 return imx233_dcp_job(ch
);
167 enum imx233_dcp_error_t
imx233_dcp_memcpy(bool fill
, const void *src
, void *dst
, size_t len
, int tmo
)
169 int chan
= imx233_dcp_acquire_channel(tmo
);
170 if(chan
== OBJ_WAIT_TIMEDOUT
)
172 enum imx233_dcp_error_t err
= imx233_dcp_memcpy_ex(chan
, fill
, src
, dst
, len
);
173 imx233_dcp_release_channel(chan
);
177 enum imx233_dcp_error_t
imx233_dcp_blit_ex(int ch
, bool fill
, const void *src
, size_t w
, size_t h
, void *dst
, size_t out_w
)
180 channel_packet
[ch
].next
= 0;
181 channel_packet
[ch
].ctrl0
= HW_DCP_CTRL0__INTERRUPT_ENABLE
|
182 HW_DCP_CTRL0__ENABLE_MEMCOPY
| HW_DCP_CTRL0__DECR_SEMAPHORE
|
183 HW_DCP_CTRL0__ENABLE_BLIT
|
184 (fill
? HW_DCP_CTRL0__CONSTANT_FILL
: 0);
185 channel_packet
[ch
].ctrl1
= out_w
;
186 channel_packet
[ch
].src
= (uint32_t)(fill
? src
: PHYSICAL_ADDR(src
));
187 channel_packet
[ch
].dst
= (uint32_t)PHYSICAL_ADDR(dst
);
188 channel_packet
[ch
].size
= w
| h
<< HW_DCP_SIZE__NUMBER_LINES_BP
;
189 channel_packet
[ch
].payload
= 0;
190 channel_packet
[ch
].status
= 0;
192 /* we have a problem here to discard the output buffer since it's not contiguous
193 * so only commit the source */
195 commit_discard_dcache_range(src
, w
* h
);
197 return imx233_dcp_job(ch
);
200 enum imx233_dcp_error_t
imx233_dcp_blit(bool fill
, const void *src
, size_t w
, size_t h
, void *dst
, size_t out_w
, int tmo
)
202 int chan
= imx233_dcp_acquire_channel(tmo
);
203 if(chan
== OBJ_WAIT_TIMEDOUT
)
205 enum imx233_dcp_error_t err
= imx233_dcp_blit_ex(chan
, fill
, src
, w
, h
, dst
, out_w
);
206 imx233_dcp_release_channel(chan
);
210 struct imx233_dcp_info_t
imx233_dcp_get_info(unsigned flags
)
212 struct imx233_dcp_info_t info
;
213 memset(&info
, 0, sizeof(info
));
214 if(flags
& DCP_INFO_CAPABILITIES
)
216 info
.has_crypto
= HW_DCP_CTRL
& HW_DCP_CTRL__PRESENT_CRYPTO
;
217 info
.has_csc
= HW_DCP_CTRL
& HW_DCP_CTRL__PRESENT_CSC
;
218 info
.num_keys
= __XTRACT(HW_DCP_CAPABILITY0
, NUM_KEYS
);
219 info
.num_channels
= __XTRACT(HW_DCP_CAPABILITY0
, NUM_CHANNELS
);
220 info
.ciphers
= __XTRACT(HW_DCP_CAPABILITY1
, CIPHER_ALGORITHMS
);
221 info
.hashs
= __XTRACT(HW_DCP_CAPABILITY1
, HASH_ALGORITHMS
);
223 if(flags
& DCP_INFO_GLOBAL_STATE
)
225 info
.otp_key_ready
= HW_DCP_STAT
& HW_DCP_STAT__OTP_KEY_READY
;
226 info
.context_switching
= HW_DCP_CTRL
& HW_DCP_CTRL__ENABLE_CONTEXT_SWITCHING
;
227 info
.context_caching
= HW_DCP_CTRL
& HW_DCP_CTRL__ENABLE_CONTEXT_CACHING
;
228 info
.gather_writes
= HW_DCP_CTRL
& HW_DCP_CTRL__GATHER_RESIDUAL_WRITES
;
229 info
.ch0_merged
= HW_DCP_CHANNELCTRL
& HW_DCP_CHANNELCTRL__CH0_IRQ_MERGED
;
231 if(flags
& DCP_INFO_CHANNELS
)
233 for(int i
= 0; i
< HW_DCP_NUM_CHANNELS
; i
++)
235 info
.channel
[i
].irq_en
= HW_DCP_CTRL
& HW_DCP_CTRL__CHANNEL_INTERRUPT_ENABLE(i
);
236 info
.channel
[i
].irq
= HW_DCP_STAT
& HW_DCP_STAT__IRQ(i
);
237 info
.channel
[i
].ready
= HW_DCP_STAT
& HW_DCP_STAT__READY_CHANNELS(i
);
238 info
.channel
[i
].high_priority
= HW_DCP_CHANNELCTRL
& HW_DCP_CHANNELCTRL__HIGH_PRIORITY_CHANNEL(i
);
239 info
.channel
[i
].enable
= HW_DCP_CHANNELCTRL
& HW_DCP_CHANNELCTRL__ENABLE_CHANNEL(i
);
240 info
.channel
[i
].sema
= __XTRACT_EX(HW_DCP_CHxSEMA(i
), HW_DCP_CHxSEMA__VALUE
);
241 info
.channel
[i
].cmdptr
= HW_DCP_CHxCMDPTR(i
);
242 info
.channel
[i
].acquired
= arbiter_acquired(&channel_arbiter
, i
);
245 if(flags
& DCP_INFO_CSC
)
247 info
.csc
.irq_en
= HW_DCP_CTRL
& HW_DCP_CTRL__CSC_INTERRUPT_ENABLE
;
248 info
.csc
.irq
= HW_DCP_STAT
& HW_DCP_STAT__CSCIRQ
;
249 info
.csc
.priority
= __XTRACT(HW_DCP_CHANNELCTRL
, CSC_PRIORITY
);
250 info
.csc
.enable
= HW_DCP_CSCCTRL0
& HW_DCP_CSCCTRL0__ENABLE
;