2 Copyright (c) 2002, Micrel Kendin Operations
4 Written 2002 by LIQUN RUAN
6 This software may be used and distributed according to the terms of
7 the GNU General Public License (GPL), incorporated herein by reference.
8 Drivers based on or derived from this code fall under the GPL and must
9 retain the authorship, copyright and license notice. This file is not
10 a complete program and may only be used when the entire operating
11 system is licensed under the GPL.
13 The author may be reached as lruan@kendin.com
14 Micrel Kendin Operations
18 This driver is for Kendin's KS8695 SOHO Router Chipset as ethernet driver.
20 Support and updates available at
21 www.kendin.com or www.micrel.com
24 #include "ks8695_drv.h"
25 #include "ks8695_cache.h"
27 /* for 922T, the values are fixed */
29 static uint32_t uICacheLineLen
= 8; /* 8 dwords, 32 bytes */
30 static uint32_t uICacheSize
= 8192; /* 8K cache size */
33 static uint32_t bPowerSaving
= FALSE
;
34 static uint32_t bAllowPowerSaving
= FALSE
;
37 * ks8695_icache_read_c9
38 * This function is use to read lockdown register
46 void ks8695_icache_read_c9(void)
51 "mrc p15, 0, %0, c9, c0, 1"
55 DRV_INFO("%s: lockdown index=%d", __FUNCTION__
, (base
>> 26));
61 * This function is use to lock given icache
64 * icache_start pointer to starting icache address
65 * icache_end pointer to ending icache address
71 int ks8695_icache_lock(void *icache_start
, void *icache_end
)
73 uint32_t victim_base
= (ICACHE_VICTIM_BASE
<< ICACHE_VICTIM_INDEX
);
75 spinlock_t lock
= SPIN_LOCK_UNLOCKED
;
78 len
= (int)(icache_end
- icache_start
);
79 DRV_INFO("%s: start=%p, end=%p, len=%d, victim=0x%x", __FUNCTION__
, icache_start
, icache_end
, len
, victim_base
);
81 /* if lockdown lines are more than half of max associtivity */
82 if ((len
/ ICACHE_BYTES_PER_LINE
) > (ICACHE_ASSOCITIVITY
>> 1)) {
83 DRV_WARN("%s: lockdown lines = %d is too many, (Assoc=%d)", __FUNCTION__
, (len
/ ICACHE_BYTES_PER_LINE
), ICACHE_ASSOCITIVITY
);
87 spin_lock_irqsave(&lock
, flags
);
91 ADRL r0, ks8695_isr \n\
92 ADRL r1, ks8695_isre \n\
94 MCR p15, 0, r2, c9, c4, 1 \n\
96 MCR p15, 0, r0, c7, c13, 1 \n\
101 ADDEQ r2, r2, #0x1<<26 \n\
102 MCREQ p15, 0, r2, c9, c0, 1 \n\
108 ADDNE r2, r2, #0x1<<26 \n\
109 MCRNE p15, 0, r2, c9, c0, 1 \n\
113 : "r0", "r1", "r2", "r3"
116 ks8695_icache_read_c9();
119 /* following are the assemble code for icache lock down, a C version should be implemented, accordingly */
120 ADRL r0
, start_address
; address pointer
122 MOV r2
, #lockdown_base<<26 ; victim pointer
123 MCR p15
, 0, r2
, c9
, c0
, 1
126 MCR p15
, 0, r0
, c7
, c13
, 1 ; prefetch ICache line
127 ADD r0
, r0
, #32 ; increment address pointer to next ICache line
129 ; do we need to increment the victim pointer
?
130 ; thest
for segment
0, and if so
, increment the victim pointer
131 ; and write the Icache victime
and lockdown base
133 AND r3
, r0
, #0x60 ; extract the segment bits from the addr.
134 CMP r3
, #0x0 ; test the segment
135 ADDEQ r2
, r2
, #0x1<<26 ; if segment 0, increment victim pointer
136 MCREQ p15
, 0, r2
, c9
, c0
, 1 ; and write ICaceh victim
and lockdown
138 ; have we linefilled enough code
?
139 ; test
for the address pointer being less than
or equal to the end_address
140 ; pointer
and if so
, loop
and perform another linefill
142 CMP r0
, r1
; test
for less than
or equal to end_address
143 BLE loop
; if not, loop
145 ; have we exited with r3 pointer to segment
0?
146 ; if so
, the ICaceh victim
and lockdown base has already been set to one higher
147 ; than the last entry written
.
148 ; if not, increment the victim pointer
and write the ICache victim
and
151 CMP r3
, #0x0 ; test for segments 1 to 3
152 ADDNE r2
, r2
, #0x1 << 26 ; if address is segment 1 to 3
153 MCRNE p15
, 0, r2
, c9
, c0
, 1 ; write ICache victim
and lockdown base
.
157 spin_unlock_irqrestore(&lock
, flags
);
164 * ks8695_icache_unlock
165 * This function is use to unlock the icache locked previously
173 void ks8695_icache_unlock(void)
176 DRV_INFO("%s", __FUNCTION__
);
182 MCR p15, 0, r1, c9, c0, 1 /* reset victim base to 0 */ \n\
186 DRV_INFO("%s", __FUNCTION__
);
190 * ks8695_icache_change_policy
191 * This function is use to change cache policy for ARM chipset
194 * bRoundRobin round robin or random mode
199 void ks8695_icache_change_policy(int bRoundRobin
)
205 mrc p15, 0, r1, c1, c0, 0 \n\
208 orrne r1, r1, #0x4000 \n\
209 biceq r1, r1, #0x4000 \n\
211 /* Write this to the control register */ \n\
212 mcr p15, 0, r1, c1, c0, 0 \n\
213 /* Make sure the pipeline is clear of any cached entries */ \n\
222 /*#ifdef DEBUG_THIS*/
223 DRV_INFO("Icache mode = %s", bRoundRobin
? "roundrobin" : "random");
228 * ks8695_enable_power_saving
229 * This function is use to enable/disable power saving
237 void ks8695_enable_power_saving(int bEnablePowerSaving
)
239 bAllowPowerSaving
= bEnablePowerSaving
;
243 * ks8695_power_saving
244 * This function is use to put ARM chipset in low power mode (wait for interrupt)
252 void ks8695_power_saving(int bSaving
)
256 /* if not allowed by configuration option */
257 if (!bAllowPowerSaving
)
261 if (bPowerSaving
== bSaving
)
264 bPowerSaving
= bSaving
;
269 mcr p15, 0, r1, c7, c0, 4 \n\
270 /* Make sure the pipeline is clear of any cached entries */ \n\
279 DRV_INFO("%s: power saving = %s", __FUNCTION__
, bSaving
? "enabled" : "disabled");