#!/usr/bin/python

import sys
import time
import os

class CMinic:
    OFFSET_EP = 0x4000
    OFFSET_PMEM = 0x8000
    OFFSET_MINIC = 0x0

    EP_REG_ECR = 0x0
    EP_REG_MACL = 0x14
    EP_REG_MACH = 0x10
    EP_REG_MDIO_CR = 0x20
    EP_REG_MDIO_SR = 0x24
    EP_REG_IDCODE = 0x28
    EP_REG_RFCR = 0x8
    EP_REG_TSCR = 0x4

    EP_MDIO_CR_RW = 0x80000000
    EP_MDIO_SR_READY = 0x80000000

    EP_ECR_TX_EN = 0x40
    EP_ECR_RX_EN = 0x80

    MINIC_REG_MCR = 0x0
    MCR_TX_START = 0x1
    MCR_TX_IDLE = 0x2
    MCR_TX_ERROR = 0x4
    MCR_RX_READY = 0x100
    MCR_RX_FULL = 0x200
    MCR_RX_EN = 0x400

    MINIC_REG_RX_ADDR = 0x8
    MINIC_REG_RX_AVAIL = 0xc
    MINIC_REG_TX_ADDR = 0x4

    MINIC_REG_EIC_IDR = 0x20
    MINIC_REG_EIC_IER = 0x24
    MINIC_REG_EIC_IMR = 0x28
    MINIC_REG_EIC_ISR = 0x2c
    MINIC_EIC_ISR_RX = 1 << 1

    TX_DESC_VALID = 1 << 31
    TX_DESC_HAS_OWN_MAC = 1 << 28



    def __init__(self, bus, base, num):
        self.base =base;
        self.bus = bus;
        self.num = num;
        self.init_ep();

    def ep_readl(self, addr):
        return self.bus.iread(0, self.base + self.OFFSET_EP + addr, 4)

    def ep_writel(self, addr, val):
        self.bus.iwrite(0, self.base + self.OFFSET_EP + addr, 4, val)

    def minic_readl(self, addr):
        return self.bus.iread(0, self.base + self.OFFSET_MINIC + addr, 4)

    def minic_writel(self, addr, val):
        self.bus.iwrite(0, self.base + self.OFFSET_MINIC + addr, 4, val)

    def pmem_writel(self, addr, val):
        self.bus.iwrite(0, self.base + self.OFFSET_PMEM + addr, 4, val)

    def pmem_readl(self, addr):
        return self.bus.iread(0, self.base + self.OFFSET_PMEM + addr, 4);
        
    def pcs_readl(self, addr):
        val = 0
        self.ep_writel(self.EP_REG_MDIO_CR, addr << 16);
        while (val & self.EP_MDIO_SR_READY) == 0:
            val = self.ep_readl(self.EP_REG_MDIO_SR)
        return (val & 0xffff)

    def start_rx(self):
        self.ep_writel(self.EP_REG_ECR, 0)
        self.ep_writel(self.EP_REG_MACL, 0xfc969b0e)
        self.ep_writel(self.EP_REG_MACH, 0x0050 + self.num)
        self.ep_writel(self.EP_REG_ECR, self.EP_ECR_TX_EN | self.EP_ECR_RX_EN)
        self.ep_writel(self.EP_REG_RFCR, 3 << 4)
        self.ep_writel(self.EP_REG_TSCR, 1 + 2)
        self.minic_writel(self.MINIC_REG_MCR, 0)
        self.minic_writel(self.MINIC_REG_RX_ADDR, 0)
        self.minic_writel(self.MINIC_REG_RX_AVAIL, 4000)
        self.minic_writel(self.MINIC_REG_EIC_IER, self.MINIC_EIC_ISR_RX)
        self.minic_writel(self.MINIC_REG_MCR, self.MCR_RX_EN)

    def init_ep(self):
        self.ep_writel(self.EP_REG_ECR, 0)
        self.ep_writel(self.EP_REG_MACL, 0xfc969b0e)
        self.ep_writel(self.EP_REG_MACH, 0x0050 + self.num)
        self.ep_writel(self.EP_REG_RFCR, 3 << 4)
        self.ep_writel(self.EP_REG_TSCR, 1 + 2)
        self.ep_writel(self.EP_REG_ECR, self.EP_ECR_TX_EN | self.EP_ECR_RX_EN)

    def test_tx(self):
        self.pmem_writel(0, (1<<31) | 64);
        self.pmem_writel(4, 0xffffffff)
        self.pmem_writel(8, 0xffffffff)
        self.pmem_writel(12, 0xffffffff)
        self.pmem_writel(16, 0xffffffff)
        self.minic_writel(self.MINIC_REG_TX_ADDR, 0);
        self.minic_writel(self.MINIC_REG_MCR, self.MCR_TX_START);

    def link_up(self):
        return self.pcs_readl(1) & 4

    def send(self) :
        # Setup TX
        self.minic_writel(self.MINIC_REG_TX_ADDR, 0);

        # Enable TX and wait for the end of the operation
        self.minic_writel(self.MINIC_REG_MCR, self.MCR_TX_START);

        mask = 1 << 1;
        while((self.minic_readl(self.MINIC_REG_MCR) & mask) == 0) :
            print "."

        mask = 1 << 2;
        if(self.minic_readl(self.MINIC_REG_MCR) & mask) :
            raise PtsError('MINIC: TX error');

    def receive(self, size) :
        # Setup RX
        self.start_rx();
        self.poll_rx();
        return self.read_buffer(size)

    def read_status(self) :
        return self.minic_readl(self.MINIC_REG_MCR);

    def poll_rx(self) :
        while(True) :
            isr = self.minic_readl(self.MINIC_REG_EIC_ISR);    
            if (isr & self.MINIC_EIC_ISR_RX) :
                # Clear interrupt!
                self.minic_writel(self.MINIC_REG_EIC_ISR, self.MINIC_EIC_ISR_RX)
                break


    def create_header_tx(self, size) :
        nwords = ((size + 1) >> 1) - 1;
        header = self.TX_DESC_VALID | nwords #| self.TX_DESC_HAS_OWN_MAC | nwords;
        return header;

    def write_buffer(self, value, size) :
        mask = 0xffffffff;
        header = self.create_header_tx(size)
        self.pmem_writel(0, header);
        for i in range(1, size) :
            tmp = (value >> (i - 1)*32) & mask;
            self.pmem_writel(i*4, tmp);

        self.pmem_writel(size*4, 0);

    def read_buffer(self, size):
        value = 0;
        mask = 0xffffffff;
        for i in range(0,size) :
            value = value | ((self.pmem_readl(i*4) & mask) << i*4);

        return value;



