diff packages/hal/powerpc/ppc40x/current/src/var_misc.c @ 1223:dbcfe4e0dbd2

New platform - TAMS MOAB - and generic changes to support it
author gthomas
date Fri, 19 Sep 2003 17:11:18 +0000
parents d2c90368aeef
children
line wrap: on
line diff
--- a/packages/hal/powerpc/ppc40x/current/src/var_misc.c
+++ b/packages/hal/powerpc/ppc40x/current/src/var_misc.c
@@ -9,6 +9,7 @@
 // -------------------------------------------
 // This file is part of eCos, the Embedded Configurable Operating System.
 // Copyright (C) 1998, 1999, 2000, 2001, 2002 Red Hat, Inc.
+// Copyright (C) 2002, 2003 Gary Thomas
 //
 // eCos is free software; you can redistribute it and/or modify it under
 // the terms of the GNU General Public License as published by the Free
@@ -56,16 +57,35 @@
 #define CYGARC_HAL_COMMON_EXPORT_CPU_MACROS
 #include <cyg/hal/ppc_regs.h>
 #include <cyg/infra/cyg_type.h>
-
+#include <cyg/hal/hal_io.h>             // I/O macros
+#include <cyg/hal/hal_if.h>             // Support (virtual vector)
 #include <cyg/hal/hal_mem.h>
+#include <cyg/infra/diag.h>
 
-void hal_ppc40x_clock_initialize(cyg_uint32 period);
+#ifdef CYGPKG_IO_PCI
+externC void hal_ppc405_pci_init(void);
+#endif
+
+externC void hal_ppc40x_clock_initialize(cyg_uint32 period);
+static  void hal_ppc405_i2c_init(void);
 
 //--------------------------------------------------------------------------
 void hal_variant_init(void)
 {
+    // Initialize I/O interfaces
+    hal_if_init();
+
+#if defined(CYGHWR_HAL_POWERPC_PPC4XX_405) || defined(CYGHWR_HAL_POWERPC_PPC4XX_405GP)
+    // Initialize I2C controller
+    hal_ppc405_i2c_init();
+#endif
+
     // Initialize real-time clock (for delays, etc, even if kernel doesn't use it)
     hal_ppc40x_clock_initialize(CYGNUM_HAL_RTC_PERIOD);
+
+#ifdef CYGPKG_IO_PCI
+    hal_ppc405_pci_init();
+#endif
 }
 
 
@@ -96,26 +116,38 @@ cyg_hal_map_memory (int id, CYG_ADDRESS 
     // There are 64 TLBs.
     max_tlbs = 64;
 
-    // Use the smallest "size" value which is big enough (round up)
-    for (sv = 0, lv = 0x400;  sv < 8;  sv++, lv <<= 2) {
-        if (lv >= size) break;        
-    }
+    // May need to use more than one slot since the TLB can only
+    // map 16MB max.
 
-    // Note: the process ID comes from the PID register (always 0)
-    epn = (virt & M_EPN_EPNMASK) | M_EPN_EV | M_EPN_SIZE(sv);
-    rpn = (phys & M_RPN_RPNMASK) | M_RPN_EX | M_RPN_WR;
+    while (size > 0) {
+        // Use the smallest "size" value which is big enough (round up)
+        for (sv = 0, lv = 0x400;  sv < 7;  sv++, lv <<= 2) {
+            if (lv >= size) break;        
+        }
+
+        // Note: the process ID comes from the PID register (always 0)
+        epn = (virt & M_EPN_EPNMASK) | M_EPN_EV | M_EPN_SIZE(sv);
+        rpn = (phys & M_RPN_RPNMASK) | M_RPN_EX | M_RPN_WR;
 
-    if (flags & CYGARC_MEMDESC_CI) {
-        rpn |= M_RPN_I;
-    }
+        if (flags & CYGARC_MEMDESC_CI) {
+            rpn |= M_RPN_I;
+        }
+#ifdef CYGSEM_HAL_DCACHE_STARTUP_MODE_WRITETHRU
+        // Only for cache-enabled regions
+        else {
+            rpn |= M_RPN_W;
+        }
+#endif
 
-    if (flags & CYGARC_MEMDESC_GUARDED) 
-        rpn |= M_RPN_G;
+        if (flags & CYGARC_MEMDESC_GUARDED) 
+            rpn |= M_RPN_G;
 
-    CYGARC_TLBWE(id, epn, rpn);
-    id++;
-
-    // Make caches default disabled when MMU is disabled.
+        CYGARC_TLBWE(id, epn, rpn);
+        id++;
+        size -= lv;
+        virt += lv;
+        phys += lv;
+    }
 
     return id;
 }
@@ -193,23 +225,137 @@ hal_ppc40x_delay_us(int us)
     cyg_uint32 pit_val1, pit_val2;
 
     delay_period = (_period * us) / 10000;
+    delay_period = ((_period / 10000) * us);
     delay = 0;
     CYGARC_MFSPR(SPR_PIT, pit_val1);
     while (delay < delay_period) {
         // Wait for clock to "tick"
         while (true) {
             CYGARC_MFSPR(SPR_PIT, pit_val2);
-            if (pit_val2 != pit_val1) break;
+            if (pit_val1 != pit_val2) break;
         }
-        if (pit_val2 > pit_val1) {
-            diff = pit_val2 - pit_val1;
+        // The counter ticks down
+        if (pit_val2 < pit_val1) {
+            diff = pit_val1 - pit_val2;
         } else {
-            diff = (pit_val2 + _period) - pit_val1;
+            diff = (_period - pit_val2) + pit_val1;
         }
         delay += diff;        
         pit_val1 = pit_val2;
     }
 }
 
+#if defined(CYGHWR_HAL_POWERPC_PPC4XX_405) || defined(CYGHWR_HAL_POWERPC_PPC4XX_405GP)
+//----------------------------------------------------------------------
+// I2C Support
+static void
+hal_ppc405_i2c_init(void)
+{
+    HAL_WRITE_UINT8(IIC0_CLKDIV, 6);  // 66MHz
+    HAL_WRITE_UINT8(IIC0_STS, (IIC0_STS_SCMP|IIC0_STS_IRQA));
+    HAL_WRITE_UINT8(IIC0_LMADR, 0);  // Clear interface
+    HAL_WRITE_UINT8(IIC0_HMADR, 0);
+    HAL_WRITE_UINT8(IIC0_LSADR, 0);
+    HAL_WRITE_UINT8(IIC0_HSADR, 0);
+    HAL_WRITE_UINT8(IIC0_EXTSTS, (IIC0_EXTSTS_IRQP|IIC0_EXTSTS_IRQD));
+    HAL_WRITE_UINT8(IIC0_MDCNTL, (IIC0_MDCNTL_FSDB|IIC0_MDCNTL_FMDB|IIC0_MDCNTL_EUBS));
+}
+
+externC bool
+hal_ppc405_i2c_put_bytes(int addr, cyg_uint8 *val, int len)
+{
+    cyg_uint8 stat, extstat, xfrcnt, cmd, size;
+    int i, j;
+
+    // The hardware can only move up to 4 bytes in a single operation
+    // This code breaks the request down into chunks of up to 4 bytes
+    // and checks the status after each chunk.
+    // Note: the actual device may impose additional size restrictions,
+    // e.g. some EEPROM devices may limit a single write to 32 bytes.
+    for (i = 0;  i < len;  i += size) {
+        HAL_WRITE_UINT8(IIC0_STS, (IIC0_STS_SCMP|IIC0_STS_IRQA));
+        HAL_WRITE_UINT8(IIC0_EXTSTS, (IIC0_EXTSTS_IRQP|IIC0_EXTSTS_IRQD));
+        HAL_WRITE_UINT8(IIC0_MDCNTL, (IIC0_MDCNTL_FSDB|IIC0_MDCNTL_FMDB));
+        cmd = IIC0_CNTL_RW_WRITE|IIC0_CNTL_PT;
+        size = (len - i);
+        if (size > 4) {
+            size = 4;
+            cmd |= IIC0_CNTL_CHT;
+        }
+        cmd |= ((size-1)<<IIC0_CNTL_TCT_SHIFT);
+        for (j = 0;  j < size;  j++) {
+            HAL_WRITE_UINT8(IIC0_MDBUF, val[i+j]);
+        }
+        HAL_WRITE_UINT8(IIC0_LMADR, addr);
+        HAL_WRITE_UINT8(IIC0_CNTL, cmd);
+        while (true) {
+            CYGACC_CALL_IF_DELAY_US(10);   // 10us
+            HAL_READ_UINT8(IIC0_STS, stat);
+            if ((stat & IIC0_STS_PT) == 0) {
+                if ((stat & IIC0_STS_ERR) != 0) {
+                    // Some sort of error
+                    HAL_READ_UINT8(IIC0_EXTSTS, extstat);                
+                    HAL_READ_UINT8(IIC0_XFRCNT, xfrcnt);                
+                    HAL_WRITE_UINT8(IIC0_EXTSTS, extstat);                
+                    HAL_WRITE_UINT8(IIC0_MDCNTL, (IIC0_MDCNTL_FSDB|IIC0_MDCNTL_FMDB));
+                    HAL_WRITE_UINT8(IIC0_STS, (IIC0_STS_SCMP|IIC0_STS_IRQA));
+                    diag_printf("%s addr: %x, len: %d, err: %x/%x, count: %d, cmd: %x\n", 
+                                __FUNCTION__, addr, len, stat, extstat, xfrcnt, cmd);
+                    diag_printf("buf: ");
+                    for (j = 0;  j < size;  j++) {
+                        diag_printf("0x%02x ", val[i+j]);
+                    }
+                    diag_printf("\n");
+                    return false;
+                }
+                break;
+            }
+        }
+    }
+    return true;
+}
+
+externC bool
+hal_ppc405_i2c_get_bytes(int addr, cyg_uint8 *val, int len)
+{
+    cyg_uint8 stat, extstat, _val, cmd;
+    int i, j, size;
+
+    for (i = 0;  i < len;  i += size) {
+        cmd = IIC0_CNTL_RW_READ|IIC0_CNTL_PT;
+        size = (len - i);
+        if (size > 4) {
+            size = 4;
+            cmd |= IIC0_CNTL_CHT;
+        }
+        cmd |= ((size-1)<<IIC0_CNTL_TCT_SHIFT);
+        HAL_WRITE_UINT8(IIC0_LMADR, addr);
+        HAL_WRITE_UINT8(IIC0_CNTL, cmd);
+        while (true) {
+            CYGACC_CALL_IF_DELAY_US(10);   // 10us
+            HAL_READ_UINT8(IIC0_STS, stat);
+            if ((stat & IIC0_STS_PT) == 0) {
+                if ((stat & IIC0_STS_ERR) != 0) {
+                    // Some sort of error
+                    HAL_READ_UINT8(IIC0_EXTSTS, extstat);                
+                    HAL_WRITE_UINT8(IIC0_EXTSTS, extstat);                
+                    HAL_WRITE_UINT8(IIC0_MDCNTL, (IIC0_MDCNTL_FSDB|IIC0_MDCNTL_FMDB));
+                    HAL_WRITE_UINT8(IIC0_STS, (IIC0_STS_SCMP|IIC0_STS_IRQA));
+                    diag_printf("%s addr: %x, len: %d, err: %x/%x\n", 
+                                __FUNCTION__, addr, len, stat, extstat);
+                    return false;
+                }
+                break;
+            }
+        }
+        for (j = 0;  j < size;  j++) {
+            HAL_READ_UINT8(IIC0_MDBUF, _val);
+            val[i+j] = _val;
+        }
+    }
+    return true;
+}
+#endif // 405
+
 //--------------------------------------------------------------------------
 // End of var_misc.c