You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

177 lines
5.9KB

  1. /***************************************************************************
  2. * Copyright (C) 2012 by George Harris *
  3. * george@luminairecoffee.com *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 2 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write to the *
  17. * Free Software Foundation, Inc., *
  18. * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
  19. ***************************************************************************/
  20. .text
  21. .syntax unified
  22. .cpu cortex-m3
  23. .thumb
  24. .thumb_func
  25. /*
  26. * Params :
  27. * r0 = start address, status (out)
  28. * r1 = count
  29. * r2 = erase command
  30. * r3 = block size
  31. */
  32. #define SSP_BASE_HIGH 0x4008
  33. #define SSP_BASE_LOW 0x3000
  34. #define SSP_CR0_OFFSET 0x00
  35. #define SSP_CR1_OFFSET 0x04
  36. #define SSP_DATA_OFFSET 0x08
  37. #define SSP_CPSR_OFFSET 0x10
  38. #define SSP_SR_OFFSET 0x0c
  39. #define SSP_CLOCK_BASE_HIGH 0x4005
  40. #define SSP_CLOCK_BASE_LOW 0x0000
  41. #define SSP_BRANCH_CLOCK_BASE_HIGH 0x4005
  42. #define SSP_BRANCH_CLOCK_BASE_LOW 0x2000
  43. #define SSP_BASE_CLOCK_OFFSET 0x94
  44. #define SSP_BRANCH_CLOCK_OFFSET 0x700
  45. #define IOCONFIG_BASE_HIGH 0x4008
  46. #define IOCONFIG_BASE_LOW 0x6000
  47. #define IOCONFIG_SCK_OFFSET 0x18c
  48. #define IOCONFIG_HOLD_OFFSET 0x190
  49. #define IOCONFIG_WP_OFFSET 0x194
  50. #define IOCONFIG_MISO_OFFSET 0x198
  51. #define IOCONFIG_MOSI_OFFSET 0x19c
  52. #define IOCONFIG_CS_OFFSET 0x1a0
  53. #define IO_BASE_HIGH 0x400f
  54. #define IO_BASE_LOW 0x4000
  55. #define IO_CS_OFFSET 0xab
  56. #define IODIR_BASE_HIGH 0x400f
  57. #define IODIR_BASE_LOW 0x6000
  58. #define IO_CS_DIR_OFFSET 0x14
  59. setup: /* Initialize SSP pins and module */
  60. mov.w r10, #IOCONFIG_BASE_LOW
  61. movt r10, #IOCONFIG_BASE_HIGH
  62. mov.w r8, #0xea
  63. str.w r8, [r10, #IOCONFIG_SCK_OFFSET] /* Configure SCK pin function */
  64. mov.w r8, #0x40
  65. str.w r8, [r10, #IOCONFIG_HOLD_OFFSET] /* Configure /HOLD pin function */
  66. mov.w r8, #0x40
  67. str.w r8, [r10, #IOCONFIG_WP_OFFSET] /* Configure /WP pin function */
  68. mov.w r8, #0xed
  69. str.w r8, [r10, #IOCONFIG_MISO_OFFSET] /* Configure MISO pin function */
  70. mov.w r8, #0xed
  71. str.w r8, [r10, #IOCONFIG_MOSI_OFFSET] /* Configure MOSI pin function */
  72. mov.w r8, #0x44
  73. str.w r8, [r10, #IOCONFIG_CS_OFFSET] /* Configure CS pin function */
  74. mov.w r10, #IODIR_BASE_LOW
  75. movt r10, #IODIR_BASE_HIGH
  76. mov.w r8, #0x800
  77. str r8, [r10, #IO_CS_DIR_OFFSET] /* Set CS as output */
  78. mov.w r10, #IO_BASE_LOW
  79. movt r10, #IO_BASE_HIGH
  80. mov.w r8, #0xff
  81. str.w r8, [r10, #IO_CS_OFFSET] /* Set CS high */
  82. mov.w r10, #SSP_CLOCK_BASE_LOW
  83. movt r10, #SSP_CLOCK_BASE_HIGH
  84. mov.w r8, #0x0000
  85. movt r8, #0x0100
  86. str.w r8, [r10, #SSP_BASE_CLOCK_OFFSET] /* Configure SSP0 base clock (use 12 MHz IRC) */
  87. mov.w r10, #SSP_BRANCH_CLOCK_BASE_LOW
  88. movt r10, #SSP_BRANCH_CLOCK_BASE_HIGH
  89. mov.w r8, #0x01
  90. str.w r8, [r10, #SSP_BRANCH_CLOCK_OFFSET] /* Configure (enable) SSP0 branch clock */
  91. mov.w r10, #SSP_BASE_LOW
  92. movt r10, #SSP_BASE_HIGH
  93. mov.w r8, #0x07
  94. str.w r8, [r10, #SSP_CR0_OFFSET] /* Set clock postscale */
  95. mov.w r8, #0x02
  96. str.w r8, [r10, #SSP_CPSR_OFFSET] /* Set clock prescale */
  97. str.w r8, [r10, #SSP_CR1_OFFSET] /* Enable SSP in SPI mode */
  98. write_enable:
  99. bl cs_down
  100. mov.w r9, #0x06 /* Send the write enable command */
  101. bl write_data
  102. bl cs_up
  103. bl cs_down
  104. mov.w r9, #0x05 /* Get status register */
  105. bl write_data
  106. mov.w r9, #0x00 /* Dummy data to clock in status */
  107. bl write_data
  108. bl cs_up
  109. tst r9, #0x02 /* If the WE bit isn't set, we have a problem. */
  110. beq error
  111. erase:
  112. bl cs_down
  113. mov.w r9, r2 /* Send the erase command */
  114. bl write_data
  115. write_address:
  116. lsr r9, r0, #16 /* Send the current 24-bit write address, MSB first */
  117. bl write_data
  118. lsr r9, r0, #8
  119. bl write_data
  120. mov.w r9, r0
  121. bl write_data
  122. bl cs_up
  123. wait_flash_busy: /* Wait for the flash to finish the previous erase */
  124. bl cs_down
  125. mov.w r9, #0x05 /* Get status register */
  126. bl write_data
  127. mov.w r9, #0x00 /* Dummy data to clock in status */
  128. bl write_data
  129. bl cs_up
  130. tst r9, #0x01 /* If it isn't done, keep waiting */
  131. bne wait_flash_busy
  132. subs r1, r1, #1 /* decrement count */
  133. cbz r1, exit /* Exit if we have written everything */
  134. add r0, r3 /* Move the address up by the block size */
  135. b write_enable /* Start a new block erase */
  136. write_data: /* Send/receive 1 byte of data over SSP */
  137. mov.w r10, #SSP_BASE_LOW
  138. movt r10, #SSP_BASE_HIGH
  139. str.w r9, [r10, #SSP_DATA_OFFSET] /* Write supplied data to the SSP data reg */
  140. wait_transmit:
  141. ldr r9, [r10, #SSP_SR_OFFSET] /* Check SSP status */
  142. tst r9, #0x0010 /* Check if BSY bit is set */
  143. bne wait_transmit /* If still transmitting, keep waiting */
  144. ldr r9, [r10, #SSP_DATA_OFFSET] /* Load received data */
  145. bx lr /* Exit subroutine */
  146. cs_up:
  147. mov.w r8, #0xff
  148. b cs_write
  149. cs_down:
  150. mov.w r8, #0x0000
  151. cs_write:
  152. mov.w r10, #IO_BASE_LOW
  153. movt r10, #IO_BASE_HIGH
  154. str.w r8, [r10, #IO_CS_OFFSET]
  155. bx lr
  156. error:
  157. movs r0, #0
  158. exit:
  159. bkpt #0x00
  160. .end