/*	$Id: i2c.S,v 1.1 2001/12/11 08:19:18 pefo Exp $ */

/*
 * Copyright (c) 2001 Opsycon AB  (www.opsycon.se)
 * 
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions
 * are met:
 * 1. Redistributions of source code must retain the above copyright
 *    notice, this list of conditions and the following disclaimer.
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 * 3. All advertising materials mentioning features or use of this software
 *    must display the following acknowledgement:
 *	This product includes software developed by Opsycon AB, Sweden.
 * 4. The name of the author may not be used to endorse or promote products
 *    derived from this software without specific prior written permission.
 *
 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS
 * OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
 * SUCH DAMAGE.
 *
 */

/*
 *   I2C Functions used in early startup code to get SPD info from
 *   SDRAM modules. This code must be entirely PIC and RAM independent.
 */

#include "pmon/dev/gt64260reg.h"
#include "target/ev64260.h"
#include <machine/mpc_regs.h>
#include <machine/psl.h>

#define	CTR	9

#define HIADJ(x)	(x)@ha
#define HI(x)		(x)@h
#define LO(x)		(x)@l

/*
 *  Use this macro to prevent reordering by as/ld and processor
 */
#define	IORDER		eieio; sync

/* Delay macro */
#define	DELAY(count)	\
	li 0, count;	\
	mtctr 0;	\
1:			\
	bdnz	1b	\

/*************************************************************
 *NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE NOTE*
 *************************************************************
 *  Throughout this code r25 is used to hold the GT-chip base
 *  address. DON'T use r25 for any purpose whatsoever!
 */

/*
 *  Macros to simplify setting up the Galileo controller
 */
#define GT_REGAD(offs) \
        ori     r5, r25, offs

#define GT_REGWR(offs, value)		\
	ori	r5, r25, offs;		\
	lis	r6, HIADJ(value);	\
	addi	r6, r6, LO(value);	\
	stwbrx	r6, 0, (r5);		\
	eieio; sync

#define GT_REGRD(offs)			\
	ori	r5, r25, offs;		\
	lwbrx	r6, 0, (r5);		\
	eieio; sync

#define GT_REGSET(offs, value)		\
	ori	r5, r25, offs;		\
	lwbrx	r6, 0, (r5);		\
	oris	r6, r6, HI(value);	\
	ori	r6, r6, LO(value);	\
	stwbrx	r6, 0, (r5);		\
	eieio; sync

#define GT_REGCLR(offs, value)		\
	ori	r5, r25, offs;		\
	lwbrx	r6, 0, (r5);		\
	lis	r5, HI(value);	\
	ori	r5, r5, LO(value);	\
	andc	r6, r6, r5;		\
	ori	r5, r25, offs;		\
	stwbrx	r6, 0, (r5);		\
	eieio; sync

#define I2C_INT_ENABLE	0x80
#define I2C_ENABLE	0x40
#define I2C_ACK		0x04
#define I2C_INT_FLAG	0x08
#define I2C_STOP_BIT	0x10
#define I2C_START_BIT	0x20

#define	I2C_AMOD_RD	0x01

#define	BUS_ERROR				0x00
#define	START_CONDITION_TRA			0x08
#define	RSTART_CONDITION_TRA			0x10
#define	ADDR_AND_WRITE_BIT_TRA_ACK_REC		0x18
#define	ADDR_AND_READ_BIT_TRA_ACK_REC		0x40
#define	SLAVE_REC_WRITE_DATA_ACK_TRA		0x28
#define	MAS_REC_READ_DATA_ACK_NOT_TRA		0x58

boot_i2c_test:
	li	r3, 0x600
boot_i2c_test_call:
	or	r7, r25, r25
	mflr	r8

	lis	r25, HI(GT_BASE_ADDR)
	bl	boot_i2c_init

	bl	boot_i2c_read

	mtlr	r8
	or	r25, r7, r7
	blr

/*
 *  Wait for interrupt, return status byte
 */
wait_int:
	GT_REGRD(I2C_CONTROL)
	li	r5, I2C_INT_FLAG
	and.	r6, r6, r5
	beq	wait_int

	GT_REGRD(I2C_STATUS_BAUDE_RATE)
	blr

/*
 *  I2C Master init.
 */

	.globl	boot_i2c_init
boot_i2c_init:

	GT_REGWR(I2C_SOFT_RESET, 0x0)
	GT_REGWR(I2C_STATUS_BAUDE_RATE, 0x24);
	GT_REGWR(I2C_CONTROL, I2C_ENABLE)

	blr

/*
 * I2C Read byte from device. Use RANDOM READ protocol.
 */

	.globl	boot_i2c_read
boot_i2c_read:

	mflr	r4				/* Save return address */

	GT_REGSET(I2C_CONTROL, I2C_START_BIT)

	bl	wait_int

	cmpwi	r6, START_CONDITION_TRA
	bne	boot_i2c_read_bad		/* Bad start, exit */
/**/
	rlwinm	r6, r3, 25, 28, 30		/* Get device part of addr */
	ori	r6, r6, 0xa0			/* Device type + write(addr) */
	GT_REGAD(I2C_DATA)			/* Send device address */
	stwbrx	r6, 0, (r5)

	GT_REGCLR(I2C_CONTROL, I2C_INT_FLAG)	/* Send it */

	bl	wait_int

	cmpwi	r6, ADDR_AND_WRITE_BIT_TRA_ACK_REC
	bne	boot_i2c_read_bad
/**/
	andi.	r6, r3, 0xff
	GT_REGAD(I2C_DATA)			/* Send address */
	stwbrx	r6, 0, (r5)
	
	GT_REGCLR(I2C_CONTROL, I2C_INT_FLAG)	/* Send it */

	bl	wait_int

	cmpwi	r6, SLAVE_REC_WRITE_DATA_ACK_TRA
	bne	boot_i2c_read_bad
/**/
	GT_REGSET(I2C_CONTROL, I2C_START_BIT)	/* Restart! */
	GT_REGCLR(I2C_CONTROL, I2C_INT_FLAG)	/* Send it */

	bl	wait_int

	cmpwi	r6, RSTART_CONDITION_TRA
	bne	boot_i2c_read_bad		/* Bad start, exit */
/**/
	rlwinm	r6, r3, 25, 28, 30		/* Get device part of addr */
	ori	r6, r6, 0xa1			/* Device type + read */
	GT_REGAD(I2C_DATA)			/* Send device address */
	stwbrx	r6, 0, (r5)

	GT_REGCLR(I2C_CONTROL, I2C_INT_FLAG)	/* Send it */

	bl	wait_int

	cmpwi	r6, ADDR_AND_READ_BIT_TRA_ACK_REC
	bne	boot_i2c_read_bad
/**/
	GT_REGCLR(I2C_CONTROL, I2C_INT_FLAG | I2C_ACK)	/* Get data */
/**/
	bl	wait_int

	cmpwi	r6, MAS_REC_READ_DATA_ACK_NOT_TRA
	bne	boot_i2c_read_bad

	GT_REGRD(I2C_DATA)

	or	r3, r6 ,r6

	b	boot_i2c_read_end
/**/
boot_i2c_read_bad:
	li	r3, -1

boot_i2c_read_end:
	GT_REGSET(I2C_CONTROL, I2C_STOP_BIT)
	GT_REGCLR(I2C_CONTROL, I2C_INT_FLAG)

	mtlr	r4
	blr
