Back to home page

LXR

 
 

    


File indexing completed on 2025-05-11 08:23:53

0001 /*
0002  * RTEMS generic MPC5200 BSP
0003  * 
0004  * RTEMS M93C64-based NV memory device driver.
0005  *
0006  * M93C46 is a serial microwire EEPROM which contains
0007  * 1Kbit (128 bytes/64 words) of non-volatile memory.
0008  * The device can be coigured for byte- or word-
0009  * access. The driver provides a file-like interface
0010  * to this memory.
0011  *
0012  * MPC5x00 PIN settings:
0013  *
0014  * PSC3_6 (output) -> MC93C46 serial data in    (D)
0015  * PSC3_7 (input)  -> MC93C46 serial data out   (Q)
0016  * PSC3_8 (output) -> MC93C46 chip select input (S)
0017  * PSC3_9 (output) -> MC93C46 serial clock      (C)
0018  *
0019  * Based on: DS1307-based Non-Volatile memory device driver from Victor V.
0020  * Vengerov.
0021  */
0022 
0023 /*
0024  * Copyright (C) 2000 OKTET Ltd.,St.-Petersburg,Russia
0025  * Author: Victor V. Vengerov
0026  * Copyright (c) 2003 IPR Engineering
0027  * Copyright (c) 2005 embedded brains GmbH & Co. KG
0028  *
0029  * The license and distribution terms for this file may be
0030  * found in the file LICENSE in this distribution or at
0031  * http://www.rtems.org/license/LICENSE.
0032  */
0033 
0034 #include <rtems.h>
0035 #include <rtems/libio.h>
0036 #include <errno.h>
0037 #include <string.h>
0038 #include <stdio.h>
0039 #include <bsp.h>
0040 #include <bsp/mpc5200.h>
0041 #include <bsp/nvram.h>
0042 #include "m93cxx.h"
0043 
0044 /*
0045  * Simple usec delay function using lower half of HARPO Time Base Register
0046  */
0047 void wait_usec(unsigned long usec)
0048   {
0049   unsigned long start_count = 0, update_count;
0050   unsigned long delay_count;
0051 
0052   if(TMBASE_CLOCK < 1000000)
0053     delay_count = (TMBASE_CLOCK * usec )/1000000;
0054   else
0055     delay_count = (TMBASE_CLOCK / 1000000) * usec;
0056 
0057   TBL_READ(start_count);
0058 
0059   update_count = start_count;
0060 
0061   while((update_count - start_count) < delay_count)
0062     TBL_READ(update_count);
0063 
0064   }
0065 
0066 
0067 /*
0068  * Enable M93Cxx chip-write
0069  */
0070 static void m93cxx_enable_write()
0071   {
0072   uint32_t header, i;
0073 
0074   ENABLE_CHIP_SELECT;
0075 
0076   WAIT(1);
0077 
0078   header = M93C46_EWEN;
0079 
0080   for(i = 0; i < M93C46_CLOCK_CYCLES; i++)
0081     {
0082 
0083     MASK_HEAD_SHIFT(header);
0084 
0085     WAIT(1);
0086 
0087     DO_CLOCK_CYCLE;
0088 
0089     WAIT(1);
0090 
0091     }
0092 
0093   DISABLE_CHIP_SELECT;
0094 
0095   return;
0096 
0097   }
0098 
0099 
0100 /*
0101  * Disable M93Cxx chip-write
0102  */
0103 static void m93cxx_disable_write()
0104   {
0105   uint32_t header, i;
0106 
0107   ENABLE_CHIP_SELECT;
0108 
0109   WAIT(1);
0110 
0111   header = M93C46_EWDS;
0112 
0113   for(i = 0; i < M93C46_CLOCK_CYCLES; i++)
0114     {
0115 
0116     MASK_HEAD_SHIFT(header);
0117 
0118     WAIT(1);
0119 
0120     DO_CLOCK_CYCLE;
0121 
0122     WAIT(1);
0123 
0124     }
0125 
0126   DISABLE_CHIP_SELECT;
0127 
0128   return;
0129 
0130   }
0131 
0132 
0133 /*
0134  * Read one byte from specified offset
0135  */
0136 static uint8_t m93cxx_read_byte(uint32_t offset)
0137   {
0138   uint8_t byte2read;
0139   uint32_t header, tmp_offset, i;
0140 #ifdef M93CXX_MODE_BYTE
0141   uint8_t byte_recv = 0;
0142 #else
0143     uint32_t word_recv = 0;
0144 #endif
0145 
0146   ENABLE_CHIP_SELECT;
0147 
0148   WAIT(1);
0149 
0150 #ifdef M93CXX_MODE_BYTE
0151 
0152   header = M93C46_READ(offset);
0153 
0154   for(i = 0; i < M93C46_CLOCK_CYCLES; i++)
0155     {
0156 
0157     MASK_HEAD_SHIFT(header);
0158 
0159     WAIT(1);
0160 
0161     DO_CLOCK_CYCLE;
0162 
0163     WAIT(1);
0164 
0165     }
0166 
0167   for(i = 0; i < 8; i++)
0168     {
0169 
0170     WAIT(1);
0171 
0172     DO_CLOCK_CYCLE;
0173 
0174     WAIT(1);
0175 
0176     GET_DATA_BYTE_SHIFT(byte_recv);
0177 
0178     }
0179 
0180   byte_recv >>= 1;
0181 
0182   byte2read = byte_recv;
0183 
0184 #else
0185   tmp_offset = offset/2;
0186 
0187   header = M93C46_READ(tmp_offset);
0188 
0189   for(i = 0; i < M93C46_CLOCK_CYCLES; i++)
0190     {
0191 
0192     MASK_HEAD_SHIFT(header);
0193 
0194     WAIT(1);
0195 
0196     DO_CLOCK_CYCLE;
0197 
0198     WAIT(1);
0199 
0200     }
0201 
0202   for(i = 0; i < 16; i++)
0203     {
0204 
0205     DO_CLOCK_CYCLE;
0206 
0207     WAIT(1);
0208 
0209     GET_DATA_WORD_SHIFT(word_recv);
0210 
0211     WAIT(1);
0212 
0213     }
0214 
0215   word_recv >>= 1;
0216 
0217   if(offset%2)
0218     {
0219 
0220     byte2read = (uint8_t)((word_recv & 0xFF00) >> 8);
0221 
0222 #ifdef NVRAM_DEBUG
0223     printf("\nbyte_read(o) = %x", byte2read);
0224 #endif
0225 
0226     }
0227   else
0228     {
0229 
0230     byte2read = (uint8_t)(word_recv & 0x00FF);
0231 
0232 #ifdef NVRAM_DEBUG
0233     printf("\nbyte_read(e) = %x", byte2read);
0234 #endif
0235     }
0236 
0237 #endif
0238 
0239   WAIT(1);
0240 
0241   DISABLE_CHIP_SELECT;
0242 
0243   return byte2read;
0244 
0245   }
0246 
0247 
0248 /*
0249  * Write one byte to specified offset
0250  */
0251 void m93cxx_write_byte(uint32_t offset, uint8_t byte2write)
0252   {
0253   uint32_t header, tmp_offset, i;
0254 #ifdef M93CXX_MODE_BYTE
0255   uint8_t byte_send;
0256 #else
0257   uint16_t word_send;
0258 #endif
0259 
0260   ENABLE_CHIP_SELECT;
0261 
0262   WAIT(1);
0263 
0264 #ifdef M93CXX_MODE_BYTE
0265   header = M93C46_WRITE(offset);
0266 
0267   for(i = 0; i < M93C46_CLOCK_CYCLES; i++)
0268     {
0269 
0270     MASK_HEAD_SHIFT(header);
0271 
0272     WAIT(1);
0273 
0274     DO_CLOCK_CYCLE;
0275 
0276     WAIT(1);
0277 
0278     }
0279 
0280   byte_send = byte2write;
0281 
0282   for(i = 0; i < 8; i++)
0283     {
0284 
0285     SET_DATA_BYTE_SHIFT(byte_send);
0286 
0287     WAIT(1);
0288 
0289     DO_CLOCK_CYCLE;
0290 
0291     WAIT(1);
0292 
0293     }
0294 
0295   }
0296 #else
0297 
0298   if(offset%2)
0299     {
0300 
0301     word_send  = (uint16_t)m93cxx_read_byte(offset-1);
0302     word_send |= (uint16_t)(m93cxx_read_byte(offset) << 8);
0303 
0304     }
0305   else
0306     {
0307 
0308     word_send  = (uint16_t)m93cxx_read_byte(offset);
0309     word_send |= (uint16_t)(m93cxx_read_byte(offset + 1) << 8);
0310 
0311     }
0312 
0313   tmp_offset = offset/2;
0314 
0315   WAIT(1);
0316 
0317   ENABLE_CHIP_SELECT;
0318 
0319   WAIT(1);
0320 
0321   header = M93C46_WRITE(tmp_offset);
0322 
0323   for(i = 0; i < M93C46_CLOCK_CYCLES; i++)
0324     {
0325 
0326     MASK_HEAD_SHIFT(header);
0327 
0328     WAIT(1);
0329 
0330     DO_CLOCK_CYCLE;
0331 
0332     WAIT(1);
0333 
0334     }
0335 
0336   if(offset%2)
0337     {
0338 
0339     word_send  = (word_send & 0x00FF) | ((uint16_t)(byte2write << 8));
0340 
0341 #ifdef NVRAM_DEBUG
0342     printf("\nword_send = %x", word_send);
0343 #endif
0344 
0345     }
0346   else
0347     {
0348 
0349     word_send  = (word_send & 0xFF00) | (uint16_t)byte2write;
0350 #ifdef NVRAM_DEBUG
0351     printf("\nword_send = %x", word_send);
0352 #endif
0353 
0354     }
0355 
0356   for(i = 0; i < 16; i++)
0357     {
0358 
0359     SET_DATA_WORD_SHIFT(word_send);
0360 
0361     WAIT(1);
0362 
0363     DO_CLOCK_CYCLE;
0364 
0365     WAIT(1);
0366 
0367     }
0368 
0369   DISABLE_CHIP_SELECT;
0370 
0371   WAIT(1);
0372 
0373   ENABLE_CHIP_SELECT;
0374 
0375   WAIT(1);
0376 
0377   CHECK_WRITE_BUSY;
0378 
0379 #endif
0380 
0381   WAIT(1);
0382 
0383   DISABLE_CHIP_SELECT;
0384 
0385   return;
0386 
0387   }
0388 
0389 
0390 /* nvram_driver_initialize --
0391  *     Non-volatile memory device driver initialization.
0392  */
0393 rtems_device_driver nvram_driver_initialize(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0394   {
0395   rtems_status_code sc;
0396 
0397   /* enable PSC3_6/PSC3_7 as general purpose pins */
0398   mpc5200.gpiosen |= (GPIO_PSC3_6 | GPIO_PSC3_7);
0399 
0400   /* PSC3_6/PSC3_7 has normal CMOS output */
0401   mpc5200.gpiosod &= ~(GPIO_PSC3_6 | GPIO_PSC3_7);
0402 
0403   /* switch PSC3_6 (MC93C46 serial data in (D)) to low */
0404   mpc5200.gpiosdo &= ~GPIO_PSC3_6;
0405 
0406   /* PSC3_6 is an output (MC93C46 serial data in (D)) and PSC3_7 (MC93C46 serial data out (Q)) is an input pin */
0407   mpc5200.gpiosdd |= GPIO_PSC3_6;
0408   mpc5200.gpiosdd &= ~GPIO_PSC3_7;
0409 
0410   /* disable PSC3_8 interrupt capabilities */
0411   mpc5200.gpiosiie &= ~GPIO_PSC3_8;
0412 
0413   /* enable PSC3_8 as general purpose pin */
0414   mpc5200.gpiosie |= GPIO_PSC3_8;
0415 
0416   /* PSC3_8 has normal CMOS output */
0417   mpc5200.gpiosiod &= ~GPIO_PSC3_8;
0418 
0419   /* switch PSC3_8 (MC93C46 chip select input (S)) to low (high activ) */
0420   mpc5200.gpiosido &= ~GPIO_PSC3_8;
0421 
0422   /* PSC3_8 is an output (MC93C46 chip select input (S)) pin */
0423   mpc5200.gpiosidd |= GPIO_PSC3_8;
0424 
0425   /* disable PSC3_9 interrupt capabilities */
0426   mpc5200.gpiowue &= ~GPIO_PSC3_9;
0427 
0428   /* enable PSC3_9 as general purpose pins */
0429   mpc5200.gpiowe |= GPIO_PSC3_9;
0430 
0431   /* PSC3_9 has normal CMOS output */
0432   mpc5200.gpiowod &= ~GPIO_PSC3_9;
0433 
0434   /* switch PSC3_9 (MC93C46 serial clock (C)) to low */
0435   mpc5200.gpiowdo &= ~GPIO_PSC3_9;
0436 
0437   /* PSC3_9 is an output (MC93C46 serial clock (C)) pin */
0438   mpc5200.gpiowdd |= GPIO_PSC3_9;
0439 
0440   sc = rtems_io_register_name("/dev/nvram", major, 0);
0441 
0442   if(sc != RTEMS_SUCCESSFUL)
0443     {
0444 
0445     errno = EIO;
0446     /*errno = ENODEV;*/
0447     return RTEMS_UNSATISFIED;
0448 
0449     }
0450   else
0451     return RTEMS_SUCCESSFUL;
0452 
0453   }
0454 
0455 
0456 /* nvram_driver_open --
0457  *     Non-volatile memory device driver open primitive.
0458  */
0459 rtems_device_driver nvram_driver_open(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0460   {
0461 
0462   return RTEMS_SUCCESSFUL;
0463 
0464   }
0465 
0466 
0467 /* nvram_driver_close --
0468  *     Non-volatile memory device driver close primitive.
0469  */
0470 rtems_device_driver nvram_driver_close(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0471   {
0472 
0473   return RTEMS_SUCCESSFUL;
0474 
0475   }
0476 
0477 
0478 /* nvram_driver_read --
0479  *     Non-volatile memory device driver read primitive.
0480  */
0481 rtems_device_driver nvram_driver_read(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0482   {
0483   rtems_libio_rw_args_t *args = arg;
0484   uint32_t count, i;
0485 
0486 #ifdef NVRAM_DEBUG
0487   printf("\nread count  = %2x", (int)(args->count));
0488   printf("\nread offset = %2x", (int)(args->offset));
0489 #endif
0490 
0491   if((args->offset >= M93C46_NVRAM_SIZE) || (args->offset + args->count > M93C46_NVRAM_SIZE))
0492     {
0493 
0494     args->bytes_moved = 0;
0495     errno = EINVAL;
0496     return RTEMS_UNSATISFIED;
0497 
0498     }
0499   else
0500     count = args->count;
0501 
0502   for(i = 0; i < count; i++)
0503     {
0504 
0505     (args->buffer)[i] = m93cxx_read_byte((args->offset) + i);
0506     (args->bytes_moved) += 1;
0507 
0508     }
0509 
0510   return RTEMS_SUCCESSFUL;
0511 
0512   }
0513 
0514 
0515 /* nvram_driver_write --
0516  *     Non-volatile memory device driver write primitive.
0517  */
0518 rtems_device_driver nvram_driver_write(rtems_device_major_number major, rtems_device_minor_number minor, void *arg)
0519   {
0520   rtems_libio_rw_args_t *args = arg;
0521   uint32_t count, i;
0522 
0523 #ifdef NVRAM_DEBUG
0524   printf("\nwrite count  = %2x", (int)(args->count));
0525   printf("\nwrite offset = %2x", (int)(args->offset));
0526 #endif
0527 
0528   if((args->offset >= M93C46_NVRAM_SIZE) || (args->offset + args->count > M93C46_NVRAM_SIZE))
0529     {
0530 
0531     args->bytes_moved = 0;
0532     errno = EINVAL;
0533     return RTEMS_UNSATISFIED;
0534 
0535     }
0536 
0537   count = args->count;
0538 
0539   m93cxx_enable_write();
0540 
0541   WAIT(1);
0542 
0543   for(i = 0; i < count; i++)
0544     {
0545 
0546     m93cxx_write_byte((args->offset) + i, (args->buffer)[i]);
0547     (args->bytes_moved) += 1;
0548 
0549     }
0550 
0551   WAIT(1);
0552 
0553   m93cxx_disable_write();
0554 
0555   return RTEMS_SUCCESSFUL;
0556 
0557   }