Contiki-NG
rom.c
1 /*
2  * Copyright (c) 2006, Swedish Institute of Computer Science
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  * 1. Redistributions of source code must retain the above copyright
9  * notice, this list of conditions and the following disclaimer.
10  * 2. Redistributions in binary form must reproduce the above copyright
11  * notice, this list of conditions and the following disclaimer in the
12  * documentation and/or other materials provided with the distribution.
13  * 3. Neither the name of the Institute nor the names of its contributors
14  * may be used to endorse or promote products derived from this software
15  * without specific prior written permission.
16  *
17  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
18  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
19  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
20  * ARE DISCLAIMED. IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
22  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
23  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
24  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
25  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
26  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27  * SUCH DAMAGE.
28  *
29  */
30 
31 #include "contiki.h"
32 
33 #include "dev/rom.h"
34 
35 struct ictx {
36  int s;
37  unsigned short ie1, ie2, wdtctl;
38 };
39 
40 static void
41 mask_intr(struct ictx *c)
42 {
43  /* Disable all interrupts. */
44  c->s = splhigh();
45 
46 #define WDTRPW 0x6900 /* Watchdog key returned by read */
47 
48  /* Disable all NMI-Interrupt sources */
49  c->wdtctl = WDTCTL;
50  c->wdtctl ^= (WDTRPW ^ WDTPW);
51  WDTCTL = WDTPW | WDTHOLD;
52  c->ie1 = IE1;
53  IE1 = 0x00;
54  c->ie2 = IE2;
55  IE2 = 0x00;
56 
57  /* MSP430F1611 257 < f < 476 kHz, 2.4576MHz/(5+1) = 409.6 kHz. */
58  FCTL2 = FWKEY | FSSEL_SMCLK | (FN2 | FN1);
59  FCTL3 = FWKEY; /* Unlock flash. */
60 }
61 
62 static void
63 rest_intr(struct ictx *c)
64 {
65  FCTL1 = FWKEY; /* Disable erase or write. */
66  FCTL3 = FWKEY | LOCK; /* Lock flash. */
67  /* Restore interrupts. */
68  IE2 = c->ie2;
69  IE1 = c->ie1;
70  WDTCTL = c->wdtctl;
71  splx(c->s);
72 }
73 
74 /*
75  * This helper routine must reside in RAM!
76  */
77 static void
78 blkwrt(void *to, const void *from, const void *from_end)
79  // __attribute__ ((section(".data")))
80  ;
81 
82 int
83 rom_erase(long nbytes, off_t offset)
84 {
85  int nb = nbytes;
86  char *to = (char *)(uintptr_t)offset;
87  struct ictx c;
88 
89  if(nbytes % ROM_ERASE_UNIT_SIZE != 0) {
90  return -1;
91  }
92 
93  if(offset % ROM_ERASE_UNIT_SIZE != 0) {
94  return -1;
95  }
96 
97  while (nbytes > 0) {
98  mask_intr(&c);
99 
100  FCTL1 = FWKEY | ERASE; /* Segment erase. */
101  *to = 0; /* Erase segment containing to. */
102  nbytes -= ROM_ERASE_UNIT_SIZE;
103  to += ROM_ERASE_UNIT_SIZE;
104 
105  rest_intr(&c);
106  }
107 
108  return nb;
109 }
110 
111 int
112 rom_pwrite(const void *buf, int nbytes, off_t offset)
113 {
114  const char *from = buf;
115  int nb = nbytes;
116  char *to = (char *)(uintptr_t)offset;
117  struct ictx c;
118 
119  mask_intr(&c);
120 
121  while(nbytes > 0) {
122  int n = (nbytes > 64) ? 64 : nbytes;
123  FCTL1 = FWKEY | BLKWRT | WRT; /* Enable block write. */
124  blkwrt(to, from, from + n);
125  while(FCTL3 & BUSY);
126  to += 64;
127  from += 64;
128  nbytes -= n;
129  }
130 
131  rest_intr(&c);
132 
133  return nb;
134 }
135 
136 /*
137  * This helper routine must reside in RAM!
138  */
139 asm(".data");
140 asm(".p2align 1,0");
141 asm(".type blkwrt,@function");
142 asm(".section .data");
143 
144 static void
145 blkwrt(void *_to, const void *_from, const void *_from_end)
146 {
147  unsigned short *to = _to;
148  const unsigned short *from = _from;
149  const unsigned short *from_end = _from_end;
150  do {
151  *to++ = *from++;
152  while(!(FCTL3 & WAIT));
153  } while(from < from_end);
154  FCTL1 = FWKEY; /* Disable block write. */
155  /* Now ROM is available again! */
156 }