/*  Code to build tags structure for the kernel
	pinched from some website somewhere
*/

#define ATAG_NONE       0x00000000
#define ATAG_CORE       0x54410001
#define ATAG_MEM        0x54410002
#define ATAG_CMDLINE    0x54410009

#define uint32 unsigned long
#define uint32_t unsigned long

/* structures for each atag */
struct atag_header {
        uint32 size; /* length of tag in words including this header */
        uint32 tag;  /* tag type */
};

struct atag_core {
        uint32 flags;
        uint32 pagesize;
        uint32 rootdev;
};

struct atag_mem {
        uint32     size;
        uint32     start;
};


struct atag_cmdline {
        char    cmdline[1];
};

struct atag {
        struct atag_header hdr;
        union {
                struct atag_core         core;
                struct atag_mem          mem;
                struct atag_cmdline      cmdline;
        } u;
};

#define tag_next(t)     ((struct atag *)((uint32 *)(t) + (t)->hdr.size))
#define tag_size(type)  ((sizeof(struct atag_header) + sizeof(struct type)) >> 2)
static struct atag *params; /* used to point at the current tag */

static void
setup_core_tag(void *address,long pagesize)
{
    params = (struct atag *)address;         /* Initialise parameters to start at given address */

    params->hdr.tag = ATAG_CORE;            /* start with the core tag */
    params->hdr.size = tag_size(atag_core); /* size the tag */

    params->u.core.flags = 1;               /* ensure read-only */
    params->u.core.pagesize = pagesize;     /* systems pagesize (4k) */
    params->u.core.rootdev = 0;             /* zero root device (typicaly overidden from commandline )*/

    params = tag_next(params);              /* move pointer to next tag */
}


static void setup_mem_tag(uint32 start, uint32 len)
{
    params->hdr.tag = ATAG_MEM;             /* Memory tag */
    params->hdr.size = tag_size(atag_mem);  /* size tag */

    params->u.mem.start = start;            /* Start of memory area (physical address) */
    params->u.mem.size = len;               /* Length of area */

    params = tag_next(params);              /* move pointer to next tag */
}

static void
setup_cmdline_tag(const char line[])
{
    int i=0;
    char *ptr = params->u.cmdline.cmdline;
    while( line[i] != 0x00){
	*(ptr+i) = line[i];
	i++;
    }

    if(i <= 0)
        return;                             /* do not insert a tag for an empty commandline */

    params->hdr.tag = ATAG_CMDLINE;         /* Commandline tag */
    params->hdr.size = (sizeof(struct atag_header) + i + 1 + 4) >> 2;

    params = tag_next(params);              /* move pointer to next tag */
}

static void
setup_end_tag(void)
{
    params->hdr.tag = ATAG_NONE;            /* Empty tag ends list */
    params->hdr.size = 0;                   /* zero length */
}

void setup_tags(void *mem){

    setup_core_tag(mem, 4096);       /* standard core tag 4k pagesize */
    setup_mem_tag(0xa0000000, 0x04000000);    /* 64Mb at 0xa0000000 */    
    setup_mem_tag(0xc0000000, 0x04000000);    /* 64Mb at 0xc0000000 */    
    //setup_cmdline_tag("root=31:0 rootfstype=jffs2 rootdelay=3 rw init=/sbin/init");	//root on flash
    setup_cmdline_tag("root=179:2 rootdelay=3 rw init=/sbin/init"); //root on mmc/sd card
    setup_end_tag();                    /* end of tags */
}
