/*
 * bootstub 32 bit entry setting routings 
 *
 * Copyright (C) 2008-2010 Intel Corporation.
 * Author: Alek Du <alek.du@intel.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms and conditions of the GNU General Public License,
 * version 2, as published by the Free Software Foundation.
 *
 * This program is distributed in the hope 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.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program; if not, write to the Free Software Foundation, Inc., 
 * 51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
 *
 */

#include "types.h"
#include "bootstub.h"
#include "bootparam.h"
#include "spi-uart.h"
#include "sfi.h"

#define bs_printk(x) { if (! *(int *)SPI_UART_SUPPRESSION) bs_spi_printk(x);}

extern int no_uart_used;

static void *memcpy(void *dest, const void *src, size_t count)
{
        char *tmp = dest;
        const char *s = src;
	size_t _count = count / 4;

	while (_count--) {
		*(long *)tmp = *(long *)s;
		tmp += 4;
		s += 4;
	}
	count %= 4;
        while (count--)
                *tmp++ = *s++;
        return dest;
}

static void *memset(void *s, unsigned char c, size_t count)
{
        char *xs = s;
	size_t _count = count / 4;
	unsigned long  _c = c << 24 | c << 16 | c << 8 | c;
 
	while (_count--) {
		*(long *)xs = _c;
		xs += 4;
	}
	count %= 4;
        while (count--)
                *xs++ = c; 
        return s;
}

static size_t strnlen(const char *s, size_t maxlen)
{
        const char *es = s;
        while (*es && maxlen) {
                es++;
                maxlen--;
        }

        return (es - s);
}

static void setup_boot_params(struct boot_params *bp, struct setup_header *sh)
{
	u8 *initramfs;
	int nr_entries;

	memset(bp, 0, sizeof (struct boot_params));
	bp->screen_info.orig_video_mode = 0;
	bp->screen_info.orig_video_lines = 0;
	bp->screen_info.orig_video_cols = 0;
	bp->alt_mem_k = 128*1024; // hard coded 128M mem here, since SFI will override it
	memcpy(&bp->hdr, sh, sizeof (struct setup_header));
	bp->hdr.cmd_line_ptr = CMDLINE_OFFSET;
	bp->hdr.cmdline_size = strnlen((const char *)CMDLINE_OFFSET, CMDLINE_SIZE);
	bp->hdr.type_of_loader = 0xff; //bootstub is unknown bootloader for kernel :)
	bp->hdr.ramdisk_size = *(u32 *)INITRD_SIZE_OFFSET;
	bp->hdr.ramdisk_image = (bp->alt_mem_k*1024 - bp->hdr.ramdisk_size) & 0xFFFFF000;
	bp->hdr.hardware_subarch = X86_SUBARCH_MRST;
	initramfs = (u8 *)BZIMAGE_OFFSET + *(u32 *)BZIMAGE_SIZE_OFFSET;
	if (*initramfs) {
		bs_printk("Relocating initramfs to high memory ...\n");
		memcpy((u8*)bp->hdr.ramdisk_image, initramfs, bp->hdr.ramdisk_size);
	} else {
		bs_printk("Won't relocate initramfs, are you in SLE?\n");
	}
	if (mid_identify_cpu() == MID_CPU_CHIP_VALLEYVIEW2) {
		nr_entries = get_e820_by_bios(bp->e820_map);
		bp->e820_entries = (nr_entries > 0) ? nr_entries : 0;
	} else {
		sfi_setup_e820(bp);
	}
}

static int get_32bit_entry(unsigned char *ptr)
{
	while (1){
		if (*(u32 *)ptr == SETUP_SIGNATURE && *(u32 *)(ptr+4) == 0)
			break;
		ptr++;
	}
	ptr+=4;
	return (((unsigned int)ptr+511)/512)*512;
}

static inline void cpuid(u32 op, u32 *eax, u32 *ebx, u32 *ecx, u32 *edx)
{
	*eax = op;
	*ecx = 0;
	asm volatile("cpuid"
		: "=a" (*eax),
		"=b" (*ebx),
		"=c" (*ecx),
		"=d" (*edx)
		: "0" (*eax), "2" (*ecx));
}

enum cpuid_regs {
	CR_EAX = 0,
	CR_ECX,
	CR_EDX,
	CR_EBX
};

int mid_identify_cpu(void)
{
	u32 regs[4];

	cpuid(1, &regs[CR_EAX], &regs[CR_EBX], &regs[CR_ECX], &regs[CR_EDX]);

	switch ( regs[CR_EAX] & CPUID_MASK ) {

	case PENWELL_FAMILY:
		return MID_CPU_CHIP_PENWELL;
	case CLOVERVIEW_FAMILY:
		return MID_CPU_CHIP_CLOVERVIEW;
	case VALLEYVIEW2_FAMILY:
		return MID_CPU_CHIP_VALLEYVIEW2;
	default:
		return MID_CPU_CHIP_OTHER;
	}
}

static void setup_spi(void)
{
	if (!(*(int *)SPI_TYPE)) {
		switch ( mid_identify_cpu() ) {

		case MID_CPU_CHIP_PENWELL:
			*(int *)SPI_TYPE = SPI_1;
			bs_printk("PNW detected\n");
			break;

		case MID_CPU_CHIP_CLOVERVIEW:
			*(int *)SPI_TYPE = SPI_1;
			bs_printk("CLV detected\n");
			break;

		case MID_CPU_CHIP_VALLEYVIEW2:
		case MID_CPU_CHIP_OTHER:
		default:
			no_uart_used = 1;
		}
	}
}

int bootstub(void)
{
	setup_spi();
	bs_printk("Bootstub Version: 1.3 ...\n");
	setup_boot_params((struct boot_params *)BOOT_PARAMS_OFFSET, 
		(struct setup_header *)SETUP_HEADER_OFFSET);
	bs_printk("Jump to kernel 32bit entry ...\n");
	return get_32bit_entry((unsigned char *)BZIMAGE_OFFSET);
}
