aboutsummaryrefslogtreecommitdiffstats
path: root/lib/lufa/Projects/AVRISP-MKII/Lib/V2Protocol.h
blob: 0f447ba4b9ecf8a4c2e12dd845c0c5e90132686e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
/*
             LUFA Library
     Copyright (C) Dean Camera, 2017.

  dean [at] fourwalledcubicle [dot] com
           www.lufa-lib.org
*/

/*
  Copyright 2017  Dean Camera (dean [at] fourwalledcubicle [dot] com)

  Permission to use, copy, modify, distribute, and sell this
  software and its documentation for any purpose is hereby granted
  without fee, provided that the above copyright notice appear in
  all copies and that both that the copyright notice and this
  permission notice and warranty disclaimer appear in supporting
  documentation, and that the name of the author not be used in
  advertising or publicity pertaining to distribution of the
  software without specific, written prior permission.

  The author disclaims all warranties with regard to this
  software, including all implied warranties of merchantability
  and fitness.  In no event shall the author be liable for any
  special, indirect or consequential damages or any damages
  whatsoever resulting from loss of use, data or profits, whether
  in an action of contract, negligence or other tortious action,
  arising out of or in connection with the use or performance of
  this software.
*/

/** \file
 *
 *  Header file for V2Protocol.c.
 */

#ifndef _V2_PROTOCOL_
#define _V2_PROTOCOL_

	/* Includes: */
		#include <avr/io.h>
		#include <avr/interrupt.h>
		#include <avr/wdt.h>

		#include <LUFA/Drivers/USB/USB.h>

		#include "../AVRISPDescriptors.h"
		#include "V2ProtocolConstants.h"
		#include "V2ProtocolParams.h"
		#include "ISP/ISPProtocol.h"
		#include "XPROG/XPROGProtocol.h"
		#include "Config/AppConfig.h"

	/* Preprocessor Checks: */
		#if ((BOARD == BOARD_XPLAIN) || (BOARD == BOARD_XPLAIN_REV1))
			#undef ENABLE_ISP_PROTOCOL

			#if !defined(ENABLE_XPROG_PROTOCOL)
				#define ENABLE_XPROG_PROTOCOL
			#endif
		#endif

		#if defined(USB_SERIES_4_AVR) && ((VTARGET_ADC_CHANNEL == 2) || (VTARGET_ADC_CHANNEL == 3)) && !defined(NO_VTARGET_DETECT)
			#error The U4 AVR chips do not contain ADC channels 2 or 3. Please change VTARGET_ADC_CHANNEL or define NO_VTARGET_DETECT in the makefile.
		#endif

		#if defined(VTARGET_USE_INTERNAL_REF)
			#undef  VTARGET_REF_VOLTS
			#define VTARGET_REF_VOLTS 2.56

			#define VTARGET_REF_MASK ADC_REFERENCE_INT2560MV
		#else
			#define VTARGET_REF_MASK ADC_REFERENCE_AVCC
		#endif

	/* Macros: */
		/** Programmer ID string, returned to the host during the CMD_SIGN_ON command processing. */
		#define PROGRAMMER_ID              "AVRISP_MK2"

		/** Timeout period for each issued command from the host before it is aborted (in 10ms ticks). */
		#define COMMAND_TIMEOUT_TICKS      100

		/** Command timeout ticks remaining counter, GPIOR for speed. */
		#define TimeoutTicksRemaining      GPIOR1

		/** MUX mask for the VTARGET ADC channel number. */
		#define VTARGET_ADC_CHANNEL_MASK   ADC_GET_CHANNEL_MASK(VTARGET_ADC_CHANNEL)

	/* External Variables: */
		extern uint32_t CurrentAddress;
		extern bool     MustLoadExtendedAddress;

	/* Function Prototypes: */
		void V2Protocol_Init(void);
		void V2Protocol_ProcessCommand(void);

		#if defined(INCLUDE_FROM_V2PROTOCOL_C)
			static void V2Protocol_UnknownCommand(const uint8_t V2Command);
			static void V2Protocol_SignOn(void);
			static void V2Protocol_GetSetParam(const uint8_t V2Command);
			static void V2Protocol_ResetProtection(void);
			static void V2Protocol_LoadAddress(void);
		#endif

#endif
tring.Symbol */ .highlight .bp { color: #003388 } /* Name.Builtin.Pseudo */ .highlight .fm { color: #0066bb; font-weight: bold } /* Name.Function.Magic */ .highlight .vc { color: #336699 } /* Name.Variable.Class */ .highlight .vg { color: #dd7700 } /* Name.Variable.Global */ .highlight .vi { color: #3333bb } /* Name.Variable.Instance */ .highlight .vm { color: #336699 } /* Name.Variable.Magic */ .highlight .il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
/*
 * apei-io.c - APEI IO memory pre-mapping/post-unmapping and access
 *
 * Copyright (C) 2009-2010, Intel Corp.
 *	Author: Huang Ying <ying.huang@intel.com>
 *	Ported by: Liu, Jinsong <jinsong.liu@intel.com>
 *
 * This program is free software; you can redistribute it and/or
 * modify it under the terms of the GNU General Public License version
 * 2 as published by the Free Software Foundation.
 *
 * 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.
 *
 * 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., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

#include <xen/kernel.h>
#include <xen/errno.h>
#include <xen/delay.h>
#include <xen/string.h>
#include <xen/xmalloc.h>
#include <xen/types.h>
#include <xen/spinlock.h>
#include <xen/list.h>
#include <xen/cper.h>
#include <xen/prefetch.h>
#include <asm/fixmap.h>
#include <asm/io.h>
#include <acpi/acpi.h>
#include <acpi/apei.h>

static LIST_HEAD(apei_iomaps);
/*
 * Used for mutual exclusion between writers of apei_iomaps list, for
 * synchronization between readers and writer.
 */
static DEFINE_SPINLOCK(apei_iomaps_lock);

struct apei_iomap {
	struct list_head list;
	void __iomem *vaddr;
	unsigned long size;
	paddr_t paddr;
};

static struct apei_iomap *__apei_find_iomap(paddr_t paddr,
					    unsigned long size)
{
	struct apei_iomap *map;

	list_for_each_entry(map, &apei_iomaps, list) {
		if (map->paddr + map->size >= paddr + size &&
		    map->paddr <= paddr)
			return map;
	}
	return NULL;
}

static void __iomem *__apei_ioremap_fast(paddr_t paddr,
					 unsigned long size)
{
	struct apei_iomap *map;

	map = __apei_find_iomap(paddr, size);
	if (map)
		return map->vaddr + (paddr - map->paddr);
	else
		return NULL;
}

static int apei_range_nr;

static void __iomem *__init apei_range_map(paddr_t paddr, unsigned long size)
{
	int i, pg;
	int start_nr, cur_nr;

	pg = ((((paddr + size -1) & PAGE_MASK)
		 - (paddr & PAGE_MASK)) >> PAGE_SHIFT) + 1;
	if (apei_range_nr + pg > FIX_APEI_RANGE_MAX)
		return NULL;

	start_nr = apei_range_nr + pg -1;
	for (i = 0; i < pg; i++) {
		cur_nr = start_nr - i;
		set_fixmap_nocache(FIX_APEI_RANGE_BASE + cur_nr,
					paddr + (i << PAGE_SHIFT));
		apei_range_nr++;
	}

	return (void __iomem *)fix_to_virt(FIX_APEI_RANGE_BASE + start_nr);
}

/*
 * Used to pre-map the specified IO memory area. First try to find
 * whether the area is already pre-mapped, if it is, return; otherwise,
 * do the real map, and add the mapping into apei_iomaps list.
 */
void __iomem *__init apei_pre_map(paddr_t paddr, unsigned long size)
{
	void __iomem *vaddr;
	struct apei_iomap *map;
	unsigned long flags;

	spin_lock_irqsave(&apei_iomaps_lock, flags);
	vaddr = __apei_ioremap_fast(paddr, size);
	spin_unlock_irqrestore(&apei_iomaps_lock, flags);
	if (vaddr)
		return vaddr;

	map = xmalloc(struct apei_iomap);
	if (!map)
		return NULL;

	vaddr = apei_range_map(paddr, size);
	if (!vaddr) {
		xfree(map);
		return NULL;
	}

	INIT_LIST_HEAD(&map->list);
	map->paddr = paddr & PAGE_MASK;
	map->size = (((paddr + size + PAGE_SIZE -1) & PAGE_MASK)
					 - (paddr & PAGE_MASK));
	map->vaddr = vaddr;

	spin_lock_irqsave(&apei_iomaps_lock, flags);
	list_add_tail(&map->list, &apei_iomaps);
	spin_unlock_irqrestore(&apei_iomaps_lock, flags);

	return map->vaddr + (paddr - map->paddr);
}

/*
 * Used to post-unmap the specified IO memory area.
 */
static void __init apei_post_unmap(paddr_t paddr, unsigned long size)
{
	struct apei_iomap *map;
	unsigned long flags;

	spin_lock_irqsave(&apei_iomaps_lock, flags);
	map = __apei_find_iomap(paddr, size);
	if (!map)
		return;

	list_del(&map->list);
	spin_unlock_irqrestore(&apei_iomaps_lock, flags);

	xfree(map);
}

/* In NMI handler, should set silent = 1 */
static int apei_check_gar(struct acpi_generic_address *reg,
			  u64 *paddr, int silent)
{
	u32 width, space_id;

	width = reg->bit_width;
	space_id = reg->space_id;
	/* Handle possible alignment issues */
	memcpy(paddr, &reg->address, sizeof(*paddr));
	if (!*paddr) {
		if (!silent)
			printk(KERN_WARNING
			"Invalid physical address in GAR\n");
		return -EINVAL;
	}

	if ((width != 8) && (width != 16) && (width != 32) && (width != 64)) {
		if (!silent)
			printk(KERN_WARNING
			"Invalid bit width in GAR\n");
		return -EINVAL;
	}

	if (space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY &&
	    space_id != ACPI_ADR_SPACE_SYSTEM_IO) {
		if (!silent)
			printk(KERN_WARNING
			"Invalid address space type in GAR\n");
		return -EINVAL;
	}

	return 0;
}

/* Pre-map, working on GAR */
int __init apei_pre_map_gar(struct acpi_generic_address *reg)
{
	u64 paddr;
	void __iomem *vaddr;
	int rc;

	if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
		return 0;

	rc = apei_check_gar(reg, &paddr, 0);
	if (rc)
		return rc;

	vaddr = apei_pre_map(paddr, reg->bit_width / 8);
	if (!vaddr)
		return -EIO;

	return 0;
}

/* Post-unmap, working on GAR */
int __init apei_post_unmap_gar(struct acpi_generic_address *reg)
{
	u64 paddr;
	int rc;

	if (reg->space_id != ACPI_ADR_SPACE_SYSTEM_MEMORY)
		return 0;

	rc = apei_check_gar(reg, &paddr, 0);
	if (rc)
		return rc;

	apei_post_unmap(paddr, reg->bit_width / 8);

	return 0;
}

static int apei_read_mem(u64 paddr, u64 *val, u32 width)
{
	void __iomem *addr;
	u64 tmpval;

	addr = __apei_ioremap_fast(paddr, width);
	switch (width) {
	case 8:
		*val = readb(addr);
		break;
	case 16:
		*val = readw(addr);
		break;
	case 32:
		*val = readl(addr);
		break;
	case 64:
		tmpval = (u64)readl(addr);
		tmpval |= ((u64)readl(addr+4)) << 32;
		*val = tmpval;
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

static int apei_write_mem(u64 paddr, u64 val, u32 width)
{
	void __iomem *addr;
	u32 tmpval;

	addr = __apei_ioremap_fast(paddr, width);
	switch (width) {
	case 8:
		writeb(val, addr);
		break;
	case 16:
		writew(val, addr);
		break;
	case 32:
		writel(val, addr);
		break;
	case 64:
		tmpval = (u32)val;
		writel(tmpval, addr);
		tmpval = (u32)(val >> 32);
		writel(tmpval, addr+4);
		break;
	default:
		return -EINVAL;
	}

	return 0;
}

int apei_read(u64 *val, struct acpi_generic_address *reg)
{
	u64 paddr;
	int rc;

	rc = apei_check_gar(reg, &paddr, 1);
	if (rc)
		return rc;

	*val = 0;

	/* currently all erst implementation take bit_width as real range */
	switch (reg->space_id) {
	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
		return apei_read_mem(paddr, val, reg->bit_width);
	case ACPI_ADR_SPACE_SYSTEM_IO:
		return acpi_os_read_port(paddr, (u32 *)val, reg->bit_width);
	default:
		return -EINVAL;
	}
}

int apei_write(u64 val, struct acpi_generic_address *reg)
{
	u64 paddr;
	int rc;

	rc = apei_check_gar(reg, &paddr, 1);
	if (rc)
		return rc;

	switch (reg->space_id) {
	case ACPI_ADR_SPACE_SYSTEM_MEMORY:
		return apei_write_mem(paddr, val, reg->bit_width);
	case ACPI_ADR_SPACE_SYSTEM_IO:
		return acpi_os_write_port(paddr, val, reg->bit_width);
	default:
		return -EINVAL;
	}
}