/*
 * This file is part of the coreboot project.
 *
 * Copyright (C) 2004 Tyan Computer
 * Written by Yinghai Lu <yhlu@tyan.com> for Tyan Computer.
 * Copyright (C) 2006,2007 AMD
 * Written by Yinghai Lu <yinghai.lu@amd.com> for AMD.
 * Copyright (C) 2007 Silicon Integrated Systems Corp. (SiS)
 * Written by Morgan Tsai <my_tsai@sis.com> for SiS.
 *
 * This program 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 Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 */

#include <console/console.h>
#include <device/device.h>
#include <delay.h>
#include <device/pci.h>
#include <device/pci_ids.h>
#include <device/pci_ops.h>
#include "sis966.h"
#include <arch/io.h>

uint8_t	SiS_SiS1183_init[68][3]={
{0x04, 0x00, 0x05},
{0x09, 0x00, 0x05},
{0x2C, 0x00, 0x39},
{0x2D, 0x00, 0x10},
{0x2E, 0x00, 0x83},
{0x2F, 0x00, 0x11},
{0x90, 0x00, 0x40},
{0x91, 0x00, 0x00},	// set mode
{0x50, 0x00, 0xA2},
{0x52, 0x00, 0xA2},
{0x55, 0x00, 0x96},
{0x52, 0x00, 0xA2},
{0x55, 0xF7, 0x00},
{0x56, 0x00, 0xC0},
{0x57, 0x00, 0x14},
{0x67, 0x00, 0x28},
{0x81, 0x00, 0xB3},
{0x82, 0x00, 0x72},
{0x83, 0x00, 0x40},
{0x85, 0x00, 0xB3},
{0x86, 0x00, 0x72},
{0x87, 0x00, 0x40},
{0x88, 0x00, 0xDE},      // after set mode
{0x89, 0x00, 0xB3},
{0x8A, 0x00, 0x72},
{0x8B, 0x00, 0x40},
{0x8C, 0x00, 0xDE},
{0x8D, 0x00, 0xB3},
{0x8E, 0x00, 0x92},
{0x8F, 0x00, 0x40},
{0x93, 0x00, 0x00},
{0x94, 0x00, 0x80},
{0x95, 0x00, 0x08},
{0x96, 0x00, 0x80},
{0x97, 0x00, 0x08},
{0x9C, 0x00, 0x80},
{0x9D, 0x00, 0x08},
{0x9E, 0x00, 0x80},
{0x9F, 0x00, 0x08},
{0xA0, 0x00, 0x15},
{0xA1, 0x00, 0x15},
{0xA2, 0x00, 0x15},
{0xA3, 0x00, 0x15},


{0xD8, 0xFE, 0x01},	// Com reset
{0xC8, 0xFE, 0x01},
{0xE8, 0xFE, 0x01},
{0xF8, 0xFE, 0x01},

{0xD8, 0xFE, 0x00},	// Com reset
{0xC8, 0xFE, 0x00},
{0xE8, 0xFE, 0x00},
{0xF8, 0xFE, 0x00},


{0xC4, 0xFF, 0xFF},    // Clear status
{0xC5, 0xFF, 0xFF},
{0xC6, 0xFF, 0xFF},
{0xC7, 0xFF, 0xFF},
{0xD4, 0xFF, 0xFF},
{0xD5, 0xFF, 0xFF},
{0xD6, 0xFF, 0xFF},
{0xD7, 0xFF, 0xFF},
{0xE4, 0xFF, 0xFF},    // Clear status
{0xE5, 0xFF, 0xFF},
{0xE6, 0xFF, 0xFF},
{0xE7, 0xFF, 0xFF},
{0xF4, 0xFF, 0xFF},
{0xF5, 0xFF, 0xFF},
{0xF6, 0xFF, 0xFF},
{0xF7, 0xFF, 0xFF},

{0x00, 0x00, 0x00}					//End of table
};

static void sata_init(struct device *dev)
{
	struct southbridge_sis_sis966_config *conf;



	conf = dev->chip_info;
        printk(BIOS_DEBUG, "SATA_INIT:---------->\n");

//-------------- enable IDE (SiS1183) -------------------------
{
        uint8_t  temp8;
        int i=0;
	while(SiS_SiS1183_init[i][0] != 0)
	{
                temp8 = pci_read_config8(dev, SiS_SiS1183_init[i][0]);
                temp8 &= SiS_SiS1183_init[i][1];
                temp8 |= SiS_SiS1183_init[i][2];
                pci_write_config8(dev, SiS_SiS1183_init[i][0], temp8);
                i++;
	};
}
//-----------------------------------------------------------

{
uint32_t i,j;
uint32_t temp32;

for (i=0;i<10;i++){
   temp32=0;
   temp32= pci_read_config32(dev, 0xC0);
   for ( j=0;j<0xFFFF;j++);
   printk(BIOS_DEBUG, "status= %x\n",temp32);
   if (((temp32&0xF) == 0x3) || ((temp32&0xF) == 0x0)) break;
}

}

#if DEBUG_SATA
{
        int i;

        printk(BIOS_DEBUG, "****** SATA PCI config ******");
        printk(BIOS_DEBUG, "\n    03020100  07060504  0B0A0908  0F0E0D0C");

        for(i=0;i<0xff;i+=4){
                if((i%16)==0)
                        printk(BIOS_DEBUG, "\n%02x: ", i);
                printk(BIOS_DEBUG, "%08x  ", pci_read_config32(dev,i));
        }
        printk(BIOS_DEBUG, "\n");
}
#endif

        printk(BIOS_DEBUG, "SATA_INIT:<----------\n");

}

static void lpci_set_subsystem(device_t dev, unsigned vendor, unsigned device)
{
	pci_write_config32(dev, 0x40,
		((device & 0xffff) << 16) | (vendor & 0xffff));
}
static struct pci_operations lops_pci = {
	.set_subsystem	= lpci_set_subsystem,
};

static struct device_operations sata_ops = {
	.read_resources	= pci_dev_read_resources,
	.set_resources	= pci_dev_set_resources,
	.enable_resources	= pci_dev_enable_resources,
//	.enable		= sis966_enable,
	.init		= sata_init,
	.scan_bus	= 0,
	.ops_pci	= &lops_pci,
};

static const struct pci_driver sata0_driver __pci_driver = {
	.ops	= &sata_ops,
	.vendor	= PCI_VENDOR_ID_SIS,
	.device	= PCI_DEVICE_ID_SIS_SIS966_SATA,
};
