1/* 2 * arch/blackfin/lib/ins.S - ins{bwl} using hardware loops 3 * 4 * Copyright 2004-2008 Analog Devices Inc. 5 * Copyright (C) 2005 Bas Vermeulen, BuyWays BV <bas@buyways.nl> 6 * Licensed under the GPL-2 or later. 7 */ 8 9#include <linux/linkage.h> 10#include <asm/blackfin.h> 11 12.align 2 13 14#ifdef CONFIG_IPIPE 15# define DO_CLI \ 16 [--sp] = rets; \ 17 [--sp] = (P5:0); \ 18 sp += -12; \ 19 call ___ipipe_disable_root_irqs_hw; \ 20 sp += 12; \ 21 (P5:0) = [sp++]; 22# define CLI_INNER_NOP 23#else 24# define DO_CLI cli R3; 25# define CLI_INNER_NOP nop; nop; nop; 26#endif 27 28#ifdef CONFIG_IPIPE 29# define DO_STI \ 30 sp += -12; \ 31 call ___ipipe_enable_root_irqs_hw; \ 32 sp += 12; \ 332: rets = [sp++]; 34#else 35# define DO_STI 2: sti R3; 36#endif 37 38#ifdef CONFIG_BFIN_INS_LOWOVERHEAD 39# define CLI_OUTER DO_CLI; 40# define STI_OUTER DO_STI; 41# define CLI_INNER 1: 42# if ANOMALY_05000416 43# define STI_INNER nop; 2: nop; 44# else 45# define STI_INNER 2: 46# endif 47#else 48# define CLI_OUTER 49# define STI_OUTER 50# define CLI_INNER 1: DO_CLI; CLI_INNER_NOP; 51# define STI_INNER DO_STI; 52#endif 53 54/* 55 * Reads on the Blackfin are speculative. In Blackfin terms, this means they 56 * can be interrupted at any time (even after they have been issued on to the 57 * external bus), and re-issued after the interrupt occurs. 58 * 59 * If a FIFO is sitting on the end of the read, it will see two reads, 60 * when the core only sees one. The FIFO receives the read which is cancelled, 61 * and not delivered to the core. 62 * 63 * To solve this, interrupts are turned off before reads occur to I/O space. 64 * There are 3 versions of all these functions 65 * - turns interrupts off every read (higher overhead, but lower latency) 66 * - turns interrupts off every loop (low overhead, but longer latency) 67 * - DMA version, which do not suffer from this issue. DMA versions have 68 * different name (prefixed by dma_ ), and are located in 69 * ../kernel/bfin_dma.c 70 * Using the dma related functions are recommended for transferring large 71 * buffers in/out of FIFOs. 72 */ 73 74#define COMMON_INS(func, ops) \ 75ENTRY(_ins##func) \ 76 P0 = R0; /* P0 = port */ \ 77 CLI_OUTER; /* 3 instructions before first read access */ \ 78 P1 = R1; /* P1 = address */ \ 79 P2 = R2; /* P2 = count */ \ 80 SSYNC; \ 81 \ 82 LSETUP(1f, 2f) LC0 = P2; \ 83 CLI_INNER; \ 84 ops; \ 85 STI_INNER; \ 86 \ 87 STI_OUTER; \ 88 RTS; \ 89ENDPROC(_ins##func) 90 91COMMON_INS(l, \ 92 R0 = [P0]; \ 93 [P1++] = R0; \ 94) 95 96COMMON_INS(w, \ 97 R0 = W[P0]; \ 98 W[P1++] = R0; \ 99) 100 101COMMON_INS(w_8, \ 102 R0 = W[P0]; \ 103 B[P1++] = R0; \ 104 R0 = R0 >> 8; \ 105 B[P1++] = R0; \ 106) 107 108COMMON_INS(b, \ 109 R0 = B[P0]; \ 110 B[P1++] = R0; \ 111) 112 113COMMON_INS(l_16, \ 114 R0 = [P0]; \ 115 W[P1++] = R0; \ 116 R0 = R0 >> 16; \ 117 W[P1++] = R0; \ 118) 119