svn commit: r304859 - in head/sys: dev/bhnd dev/bhnd/bcma dev/bhnd/cores/chipc mips/broadcom

Landon J. Fuller landonf at FreeBSD.org
Fri Aug 26 20:16:04 UTC 2016


Author: landonf
Date: Fri Aug 26 20:16:02 2016
New Revision: 304859
URL: https://svnweb.freebsd.org/changeset/base/304859

Log:
  [mips/broadcom] Generic platform_reset() support.
  
  This adds support for performing platform_reset() on all supported
  devices, using early boot enumeration of chipc capabilities and
  available cores.
  
  
  - Added Broadcom-specific MIPS CP0 register definitions used by
    BCM4785-specific reset handling.
  - Added a bcm_platform structure for tracking chipc/pmu/cfe platform
    data.
  - Extended the BCMA EROM API to support early boot lookup of core info
    (including port/region mappings).
  - Extended platform_reset() to support PMU, PMU+AOB, and non-PMU
    devices.
  
  Reviewed by:	mizhka
  Approved by:	adrian (mentor)
  Differential Revision:	https://reviews.freebsd.org/D7539

Added:
  head/sys/mips/broadcom/bcm_bcma.c   (contents, props changed)
  head/sys/mips/broadcom/bcm_machdep.h   (contents, props changed)
  head/sys/mips/broadcom/bcm_mips_exts.h   (contents, props changed)
  head/sys/mips/broadcom/bcm_siba.c   (contents, props changed)
Modified:
  head/sys/dev/bhnd/bcma/bcma_erom.c
  head/sys/dev/bhnd/bcma/bcma_eromvar.h
  head/sys/dev/bhnd/bhnd_ids.h
  head/sys/dev/bhnd/bhnd_subr.c
  head/sys/dev/bhnd/cores/chipc/chipcreg.h
  head/sys/mips/broadcom/bcm_machdep.c
  head/sys/mips/broadcom/bcm_socinfo.c
  head/sys/mips/broadcom/bcm_socinfo.h
  head/sys/mips/broadcom/files.broadcom
  head/sys/mips/broadcom/uart_cpu_chipc.c

Modified: head/sys/dev/bhnd/bcma/bcma_erom.c
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma_erom.c	Fri Aug 26 20:15:22 2016	(r304858)
+++ head/sys/dev/bhnd/bcma/bcma_erom.c	Fri Aug 26 20:16:02 2016	(r304859)
@@ -65,10 +65,18 @@ static int		 erom_skip_mport(struct bcma
 static int		 erom_skip_sport_region(struct bcma_erom *erom);
 
 static int		 erom_seek_next(struct bcma_erom *erom, uint8_t etype);
+static int		 erom_region_to_port_type(struct bcma_erom *erom,
+			    uint8_t region_type, bhnd_port_type *port_type);
 
-#define	EROM_LOG(erom, fmt, ...)	\
-	device_printf(erom->dev, "erom[0x%llx]: " fmt, \
-	    (unsigned long long) (erom->offset), ##__VA_ARGS__);
+#define	EROM_LOG(erom, fmt, ...)	do {				\
+	if (erom->dev != NULL) {					\
+		device_printf(erom->dev, "erom[0x%llx]: " fmt,		\
+		    (unsigned long long) (erom->offset), ##__VA_ARGS__);\
+	} else {							\
+		printf("erom[0x%llx]: " fmt,				\
+		    (unsigned long long) (erom->offset), ##__VA_ARGS__);\
+	}								\
+} while(0)
 
 /**
  * Open an EROM table for reading.
@@ -82,11 +90,37 @@ static int		 erom_seek_next(struct bcma_
  * @retval non-zero if the erom table could not be opened.
  */
 int
-bcma_erom_open(struct bcma_erom *erom, struct resource *r, bus_size_t offset)
+bcma_erom_open(struct bcma_erom *erom, struct resource *r,
+    bus_size_t offset)
+{
+	return (bhnd_erom_bus_space_open(erom, rman_get_device(r),
+	    rman_get_bustag(r), rman_get_bushandle(r), offset));
+
+	return (0);
+}
+
+/**
+ * Open an EROM table for reading using the provided bus space tag and
+ * handle.
+ * 
+ * @param[out] erom On success, will be populated with a valid EROM
+ * read state.
+ * @param dev The owning device, or NULL if none.
+ * @param bst EROM table bus space tag.
+ * @param bsh EROM table bus space handle.
+ * @param offset Offset of the EROM core from @p resource.
+ *
+ * @retval 0 success
+ * @retval non-zero if the erom table could not be opened.
+ */
+int
+bhnd_erom_bus_space_open(struct bcma_erom *erom, device_t dev,
+    bus_space_tag_t bst, bus_space_handle_t bsh, bus_size_t offset)
 {
 	/* Initialize the EROM reader */
-	erom->dev = rman_get_device(r);
-	erom->r = r;
+	erom->dev = dev;
+	erom->bst = bst;
+	erom->bsh = bsh;
 	erom->start = offset + BCMA_EROM_TABLE_START;
 	erom->offset = 0;
 
@@ -145,7 +179,8 @@ bcma_erom_peek32(struct bcma_erom *erom,
 		return (EINVAL);
 	}
 
-	*entry = bus_read_4(erom->r, erom->start + erom->offset);
+	*entry = bus_space_read_4(erom->bst, erom->bsh,
+	    erom->start + erom->offset);
 	return (0);
 }
 
@@ -300,6 +335,20 @@ bcma_erom_reset(struct bcma_erom *erom)
 }
 
 /**
+ * Seek to the next core entry.
+ * 
+ * @param erom EROM read state.
+ * @retval 0 success
+ * @retval ENOENT The end of the EROM table was reached.
+ * @retval non-zero Reading or parsing failed.
+ */
+int
+bcma_erom_seek_next_core(struct bcma_erom *erom)
+{
+	return (erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE));
+}
+
+/**
  * Seek to the requested core entry.
  * 
  * @param erom EROM read state.
@@ -387,6 +436,153 @@ bcma_erom_parse_core(struct bcma_erom *e
 }
 
 /**
+ * Seek to a region record associated with @p core_index.
+ * 
+ * @param erom EROM read state.
+ * @param core_index The index of the core record to be searched.
+ * @param port_type The port type to search for.
+ * @param port_num The port number to search for.
+ * @param region_num The region number to search for.
+ * @retval 0 success
+ * @retval ENOENT The requested region was not found.
+ * @retval non-zero Reading or parsing failed.
+ */
+int
+bcma_erom_seek_core_sport_region(struct bcma_erom *erom, u_int core_index,
+    bhnd_port_type port_type, u_int port_num, u_int region_num)
+{
+	struct bcma_erom_core	core;
+	uint32_t		entry;
+	uint8_t			region_port, region_type;
+	bool			found;
+	int			error;
+
+	if ((error = bcma_erom_seek_core_index(erom, core_index)))
+		return (error);
+
+	if ((error = bcma_erom_parse_core(erom, &core)))
+		return (error);
+
+	/* Skip master ports */
+	for (u_long i = 0; i < core.num_mport; i++) {
+		if ((error = erom_skip_mport(erom)))
+			return (error);
+	}
+
+	/* Seek to the region block for the given port type */
+	found = false;
+	while (1) {
+		bhnd_port_type	p_type;
+		uint8_t		r_type;
+
+		if ((error = bcma_erom_peek32(erom, &entry)))
+			return (error);
+
+		if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+			return (ENOENT);
+
+		/* Expected region type? */
+		r_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+		if ((error = erom_region_to_port_type(erom, r_type, &p_type)))
+			return (error);
+
+		if (p_type == port_type) {
+			found = true;
+			break;
+		}
+
+		/* Skip to next entry */
+		if ((error = erom_skip_sport_region(erom)))
+			return (error);
+	}
+
+	if (!found)
+		return (ENOENT);
+
+	/* Found the appropriate port type block; now find the region records
+	 * for the given port number */
+	found = false;
+	for (u_int i = 0; i <= port_num; i++) {
+		bhnd_port_type	p_type;
+
+		if ((error = bcma_erom_peek32(erom, &entry)))
+			return (error);
+		
+		if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+			return (ENOENT);
+
+		/* Fetch the type/port of the first region entry */
+		region_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+		region_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
+
+		/* Have we found the region entries for the desired port? */
+		if (i == port_num) {
+			error = erom_region_to_port_type(erom, region_type,
+			    &p_type);
+			if (error)
+				return (error);
+
+			if (p_type == port_type)
+				found = true;
+
+			break;
+		}
+
+		/* Otherwise, seek to next block of region records */
+		while (1) {
+			uint8_t	next_type, next_port;
+	
+			if ((error = erom_skip_sport_region(erom)))
+				return (error);
+
+			if ((error = bcma_erom_peek32(erom, &entry)))
+				return (error);
+
+			if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+				return (ENOENT);
+
+			next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+			next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
+
+			if (next_type != region_type ||
+			    next_port != region_port)
+				break;
+		}
+	}
+
+	if (!found)
+		return (ENOENT);
+
+	/* Finally, search for the requested region number */
+	for (u_int i = 0; i <= region_num; i++) {
+		uint8_t	next_port, next_type;
+
+		if ((error = bcma_erom_peek32(erom, &entry)))
+			return (error);
+		
+		if (!BCMA_EROM_ENTRY_IS(entry, REGION))
+			return (ENOENT);
+
+		/* Check for the end of the region block */
+		next_type = BCMA_EROM_GET_ATTR(entry, REGION_TYPE);
+		next_port = BCMA_EROM_GET_ATTR(entry, REGION_PORT);
+
+		if (next_type != region_type ||
+		    next_port != region_port)
+			break;
+
+		if (i == region_num)
+			return (0);
+
+		if ((error = erom_skip_sport_region(erom)))
+			return (error);
+	}
+
+	/* Not found */
+	return (ENOENT);
+}
+
+/**
  * Read the next master port descriptor from the EROM table.
  * 
  * @param erom EROM read state.
@@ -492,6 +688,25 @@ bcma_erom_parse_sport_region(struct bcma
 }
 
 /**
+ * Convert a bcma_erom_core record to its bhnd_core_info representation.
+ * 
+ * @param core EROM core record to convert.
+ * @param core_idx The core index of @p core.
+ * @param core_unit The core unit of @p core.
+ * @param[out] info The populated bhnd_core_info representation.
+ */
+void
+bcma_erom_to_core_info(const struct bcma_erom_core *core, u_int core_idx,
+    int core_unit, struct bhnd_core_info *info)
+{
+	info->vendor = core->vendor;
+	info->device = core->device;
+	info->hwrev = core->rev;
+	info->core_idx = core_idx;
+	info->unit = core_unit;
+}
+
+/**
  * Parse all cores descriptors from @p erom and return the array
  * in @p cores and the count in @p num_cores. The current EROM read position
  * is left unmodified.
@@ -545,7 +760,8 @@ bcma_erom_get_core_info(struct bcma_erom
 	/* Parse all core descriptors */
 	bcma_erom_reset(erom);
 	for (u_int i = 0; i < count; i++) {
-		struct bcma_erom_core core;
+		struct bcma_erom_core	core;
+		int			unit;
 
 		/* Parse the core */
 		error = erom_seek_next(erom, BCMA_EROM_ENTRY_TYPE_CORE);
@@ -555,20 +771,17 @@ bcma_erom_get_core_info(struct bcma_erom
 		error = bcma_erom_parse_core(erom, &core);
 		if (error)
 			goto cleanup;
-		
-		/* Convert to a bhnd info record */
-		buffer[i].vendor = core.vendor;
-		buffer[i].device = core.device;
-		buffer[i].hwrev = core.rev;
-		buffer[i].core_idx = i;
-		buffer[i].unit = 0;
 
 		/* Determine the unit number */
+		unit = 0;
 		for (u_int j = 0; j < i; j++) {
 			if (buffer[i].vendor == buffer[j].vendor &&
 			    buffer[i].device == buffer[j].device)
-				buffer[i].unit++;
+				unit++;
 		}
+
+		/* Convert to a bhnd info record */
+		bcma_erom_to_core_info(&core, i, unit, &buffer[i]);
 	}
 
 cleanup:
@@ -585,6 +798,33 @@ cleanup:
 	return (error);
 }
 
+/**
+ * Map an EROM region type to its corresponding port type.
+ * 
+ * @param region_type Region type value.
+ * @param[out] port_type On success, the corresponding port type.
+ */
+static int
+erom_region_to_port_type(struct bcma_erom *erom, uint8_t region_type,
+    bhnd_port_type *port_type)
+{
+	switch (region_type) {
+	case BCMA_EROM_REGION_TYPE_DEVICE:
+		*port_type = BHND_PORT_DEVICE;
+		return (0);
+	case BCMA_EROM_REGION_TYPE_BRIDGE:
+		*port_type = BHND_PORT_BRIDGE;
+		return (0);
+	case BCMA_EROM_REGION_TYPE_MWRAP:
+	case BCMA_EROM_REGION_TYPE_SWRAP:
+		*port_type = BHND_PORT_AGENT;
+		return (0);
+	default:
+		EROM_LOG(erom, "unsupported region type %hhx\n",
+			region_type);
+		return (EINVAL);
+	}
+}
 
 /**
  * Register all MMIO region descriptors for the given slave port.
@@ -608,24 +848,10 @@ erom_corecfg_fill_port_regions(struct bc
 	bhnd_port_type		 port_type;
 
 	error = 0;
-	
+
 	/* Determine the port type for this region type. */
-	switch (region_type) {
-		case BCMA_EROM_REGION_TYPE_DEVICE:
-			port_type = BHND_PORT_DEVICE;
-			break;
-		case BCMA_EROM_REGION_TYPE_BRIDGE:
-			port_type = BHND_PORT_BRIDGE;
-			break;
-		case BCMA_EROM_REGION_TYPE_MWRAP:
-		case BCMA_EROM_REGION_TYPE_SWRAP:
-			port_type = BHND_PORT_AGENT;
-			break;
-		default:
-			EROM_LOG(erom, "unsupported region type %hhx\n",
-			    region_type);
-			return (EINVAL);
-	}
+	if ((error = erom_region_to_port_type(erom, region_type, &port_type)))
+		return (error);
 
 	/* Fetch the list to be populated */
 	sports = bcma_corecfg_get_port_list(corecfg, port_type);

Modified: head/sys/dev/bhnd/bcma/bcma_eromvar.h
==============================================================================
--- head/sys/dev/bhnd/bcma/bcma_eromvar.h	Fri Aug 26 20:15:22 2016	(r304858)
+++ head/sys/dev/bhnd/bcma/bcma_eromvar.h	Fri Aug 26 20:16:02 2016	(r304859)
@@ -40,10 +40,11 @@
  * EROM read context.
  */
 struct bcma_erom {
-	device_t	 dev;		/**< EROM parent device */
-	struct resource	*r;		/**< EROM table resource. */
-	bus_size_t	 start;		/**< EROM table offset */
-	bus_size_t	 offset;	/**< current read offset */
+	device_t	 	dev;		/**< EROM parent device */
+	bus_space_tag_t		bst;		/**< EROM table bus space */
+	bus_space_handle_t	bsh;		/**< EROM table bus handle */
+	bus_size_t	 	start;		/**< EROM table offset */
+	bus_size_t	 	offset;		/**< current read offset */
 };
 
 /** EROM core descriptor. */
@@ -78,22 +79,34 @@ struct bcma_erom_sport_region {
 int		bcma_erom_open(struct bcma_erom *erom, struct resource *r,
 		    bus_size_t offset);
 
+int		bhnd_erom_bus_space_open(struct bcma_erom *erom, device_t owner,
+		    bus_space_tag_t bst, bus_space_handle_t bsh,
+		    bus_size_t offset);
+
 int		bcma_erom_peek32(struct bcma_erom *erom, uint32_t *entry);
 bus_size_t	bcma_erom_tell(struct bcma_erom *erom);
 void		bcma_erom_seek(struct bcma_erom *erom, bus_size_t offset);
 void		bcma_erom_reset(struct bcma_erom *erom);
 
+int		bcma_erom_seek_next_core(struct bcma_erom *erom);
 int		bcma_erom_seek_core_index(struct bcma_erom *erom,
 		    u_int core_index);
 int		bcma_erom_parse_core(struct bcma_erom *erom,
 		    struct bcma_erom_core *core);
 
+int		bcma_erom_seek_core_sport_region(struct bcma_erom *erom,
+		    u_int core_index, bhnd_port_type port_type, u_int port_num,
+		    u_int region_num);
+
 int		bcma_erom_parse_mport(struct bcma_erom *erom,
 		    struct bcma_erom_mport *mport);
 
 int		bcma_erom_parse_sport_region(struct bcma_erom *erom,
 		    struct bcma_erom_sport_region *region);
 
+void		bcma_erom_to_core_info(const struct bcma_erom_core *core,
+		    u_int core_idx, int core_unit, struct bhnd_core_info *info);
+
 int		bcma_erom_get_core_info(struct bcma_erom *erom,
 		    struct bhnd_core_info **cores,
 		    u_int *num_cores);

Modified: head/sys/dev/bhnd/bhnd_ids.h
==============================================================================
--- head/sys/dev/bhnd/bhnd_ids.h	Fri Aug 26 20:15:22 2016	(r304858)
+++ head/sys/dev/bhnd/bhnd_ids.h	Fri Aug 26 20:16:02 2016	(r304859)
@@ -535,6 +535,12 @@
 #define	BHND_CHIPTYPE_UBUS		2		/**< ubus interconnect found in bcm63xx devices */
 #define	BHND_CHIPTYPE_BCMA_ALT		3		/**< bcma(4) interconnect */
 
+/** Evaluates to true if @p _type uses a BCMA EROM table */
+#define	BHND_CHIPTYPE_HAS_EROM(_type)		\
+	((_type) == BHND_CHIPTYPE_BCMA ||	\
+	 (_type) == BHND_CHIPTYPE_BCMA_ALT ||	\
+	 (_type) == BHND_CHIPTYPE_UBUS)
+
 /* Boardflags */
 #define	BHND_BFL_BTC2WIRE		0x00000001	/* old 2wire Bluetooth coexistence, OBSOLETE */
 #define	BHND_BFL_BTCOEX			0x00000001	/* Board supports BTCOEX */

Modified: head/sys/dev/bhnd/bhnd_subr.c
==============================================================================
--- head/sys/dev/bhnd/bhnd_subr.c	Fri Aug 26 20:15:22 2016	(r304858)
+++ head/sys/dev/bhnd/bhnd_subr.c	Fri Aug 26 20:16:02 2016	(r304859)
@@ -834,12 +834,16 @@ bhnd_read_chipid(device_t dev, struct re
     bus_size_t chipc_offset, struct bhnd_chipid *result)
 {
 	struct resource			*res;
+	bhnd_addr_t			 enum_addr;
 	uint32_t			 reg;
+	uint8_t				 chip_type;
 	int				 error, rid, rtype;
 
-	/* Allocate the ChipCommon window resource and fetch the chipid data */
 	rid = rs->rid;
 	rtype = rs->type;
+	error = 0;
+
+	/* Allocate the ChipCommon window resource and fetch the chipid data */
 	res = bus_alloc_resource_any(dev, rtype, &rid, RF_ACTIVE);
 	if (res == NULL) {
 		device_printf(dev,
@@ -849,30 +853,23 @@ bhnd_read_chipid(device_t dev, struct re
 
 	/* Fetch the basic chip info */
 	reg = bus_read_4(res, chipc_offset + CHIPC_ID);
-	*result = bhnd_parse_chipid(reg, 0x0);
+	chip_type = CHIPC_GET_BITS(reg, CHIPC_ID_BUS);
 
-	/* Fetch the enum base address */
-	error = 0;
-	switch (result->chip_type) {
-	case BHND_CHIPTYPE_SIBA:
-		result->enum_addr = BHND_DEFAULT_CHIPC_ADDR;
-		break;
-	case BHND_CHIPTYPE_BCMA:
-	case BHND_CHIPTYPE_BCMA_ALT:
-		result->enum_addr = bus_read_4(res, chipc_offset +
-		    CHIPC_EROMPTR);
-		break;
-	case BHND_CHIPTYPE_UBUS:
-		device_printf(dev, "unsupported ubus/bcm63xx chip type");
-		error = ENODEV;
-		goto cleanup;
-	default:
-		device_printf(dev, "unknown chip type %hhu\n",
-		    result->chip_type);
+	/* Fetch the EROMPTR */
+	if (BHND_CHIPTYPE_HAS_EROM(chip_type)) {
+		enum_addr = bus_read_4(res, chipc_offset + CHIPC_EROMPTR);
+	} else if (chip_type == BHND_CHIPTYPE_SIBA) {
+		/* siba(4) uses the ChipCommon base address as the enumeration
+		 * address */
+		enum_addr = rman_get_start(res) + chipc_offset;
+	} else {
+		device_printf(dev, "unknown chip type %hhu\n", chip_type);
 		error = ENODEV;
 		goto cleanup;
 	}
 
+	*result = bhnd_parse_chipid(reg, enum_addr);
+
 cleanup:
 	/* Clean up */
 	bus_release_resource(dev, rtype, rid, res);

Modified: head/sys/dev/bhnd/cores/chipc/chipcreg.h
==============================================================================
--- head/sys/dev/bhnd/cores/chipc/chipcreg.h	Fri Aug 26 20:15:22 2016	(r304858)
+++ head/sys/dev/bhnd/cores/chipc/chipcreg.h	Fri Aug 26 20:16:02 2016	(r304859)
@@ -35,6 +35,16 @@
  *  the core count via the chip identification register. */
 #define	CHIPC_NCORES_MIN_HWREV(hwrev)	((hwrev) == 4 || (hwrev) >= 6)
 
+/** Evaluates to true if the given ChipCommon core revision supports
+ *  the CHIPC_CAPABILITIES_EXT register */
+#define	CHIPC_HWREV_HAS_CAP_EXT(hwrev)	((hwrev) >= 35)
+
+/** Evaluates to true if the chipcommon core (determined from the provided
+ * @p _chipid (CHIPC_ID) register value) provides a pointer to the enumeration
+ * table via CHIPC_EROMPTR */
+#define	CHIPC_HAS_EROMPTR(_chipid)	\
+	(CHIPC_GET_BITS((_chipid), CHIPC_ID_BUS) != BHND_CHIPTYPE_SIBA)
+
 #define CHIPC_GET_FLAG(_value, _flag)	(((_value) & _flag) != 0)
 #define	CHIPC_GET_BITS(_value, _field)	\
 	((_value & _field ## _MASK) >> _field ## _SHIFT)

Added: head/sys/mips/broadcom/bcm_bcma.c
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/broadcom/bcm_bcma.c	Fri Aug 26 20:16:02 2016	(r304859)
@@ -0,0 +1,100 @@
+/*-
+ * Copyright (c) 2016 Landon Fuller <landonf at FreeBSD.org>
+ *
+ * All rights reserved.
+ *
+ * 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.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``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 OR CONTRIBUTORS 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.
+ */
+
+#include <sys/cdefs.h>
+__FBSDID("$FreeBSD$");
+
+#include <sys/types.h>
+
+#include <machine/bus.h>
+
+#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/bcma/bcma_eromvar.h>
+
+#include "bcm_machdep.h"
+
+#define	BCMFC_ERR(fmt, ...)	printf("%s: " fmt, __FUNCTION__, ##__VA_ARGS__)
+
+int
+bcm_find_core_bcma(struct bhnd_chipid *chipid, bhnd_devclass_t devclass,
+    int unit, struct bhnd_core_info *info, uintptr_t *addr)
+{
+	struct bcma_erom		erom;
+	struct bcma_erom_core		core;
+	struct bcma_erom_sport_region	region;
+	bhnd_devclass_t			core_class;
+	int				error;
+
+	error = bhnd_erom_bus_space_open(&erom, NULL, mips_bus_space_generic,
+	    (bus_space_handle_t) BCM_SOC_ADDR(chipid->enum_addr, 0), 0);
+	if (error) {
+		BCMFC_ERR("erom open failed: %d\n", error);
+		return (error);
+	}
+
+	for (u_long core_index = 0; core_index < ULONG_MAX; core_index++) {
+		/* Fetch next core record */
+		if ((error = bcma_erom_seek_next_core(&erom)))
+			return (error);
+
+		if ((error = bcma_erom_parse_core(&erom, &core))) {
+			BCMFC_ERR("core parse failed: %d\n", error);
+			return (error);
+		}
+
+		/* Check for match */
+		core_class = bhnd_find_core_class(core.vendor,
+		    core.device);
+		if (core_class != devclass)
+			continue;
+
+		/* Provide the basic core info */
+		if (info != NULL)
+			bcma_erom_to_core_info(&core, core_index, 0, info);
+
+		/* Provide the core's device0.0 port address */
+		error = bcma_erom_seek_core_sport_region(&erom, core_index,
+		    BHND_PORT_DEVICE, 0, 0);
+		if (error) {
+			BCMFC_ERR("sport not found: %d\n", error);
+			return (error);
+		}
+
+		if ((error = bcma_erom_parse_sport_region(&erom, &region))) {
+			BCMFC_ERR("sport parse failed: %d\n", error);
+			return (error);
+		}
+
+		if (addr != NULL)
+			*addr = region.base_addr;
+
+		return (0);
+	}
+
+	/* Not found */
+	return (ENOENT);
+}

Modified: head/sys/mips/broadcom/bcm_machdep.c
==============================================================================
--- head/sys/mips/broadcom/bcm_machdep.c	Fri Aug 26 20:15:22 2016	(r304858)
+++ head/sys/mips/broadcom/bcm_machdep.c	Fri Aug 26 20:16:02 2016	(r304859)
@@ -1,6 +1,7 @@
 /*-
  * Copyright (c) 2007 Bruce M. Simpson.
  * Copyright (c) 2016 Michael Zhilin <mizhka at gmail.com>
+ * Copyright (c) 2016 Landon Fuller <landonf at FreeBSD.org>
  *
  * All rights reserved.
  *
@@ -71,6 +72,18 @@ __FBSDID("$FreeBSD$");
 #include <machine/trap.h>
 #include <machine/vmparam.h>
 
+#include <dev/bhnd/bhnd.h>
+#include <dev/bhnd/bhndreg.h>
+
+#include <dev/bhnd/bcma/bcma_eromvar.h>
+
+#include <dev/bhnd/siba/sibareg.h>
+#include <dev/bhnd/siba/sibavar.h>
+
+#include <dev/bhnd/cores/chipc/chipcreg.h>
+
+#include "bcm_machdep.h"
+#include "bcm_mips_exts.h"
 #include "bcm_socinfo.h"
 
 #ifdef CFE
@@ -83,8 +96,150 @@ __FBSDID("$FreeBSD$");
 #define	BCM_TRACE(_fmt, ...)
 #endif
 
-extern int *edata;
-extern int *end;
+static int	bcm_find_core(struct bhnd_chipid *chipid,
+		    bhnd_devclass_t devclass, int unit,
+		    struct bhnd_core_info *info, uintptr_t *addr);
+static int	bcm_init_platform_data(struct bcm_platform *pdata);
+
+/* Allow bus-specific implementations to override bcm_find_core_(bcma|siba)
+ * symbols, if included in the kernel build */
+__weak_reference(bcm_find_core_default, bcm_find_core_bcma);
+__weak_reference(bcm_find_core_default, bcm_find_core_siba);
+
+extern int	*edata;
+extern int	*end;
+
+static struct bcm_platform	 bcm_platform_data;
+static bool			 bcm_platform_data_avail = false;
+
+struct bcm_platform *
+bcm_get_platform(void)
+{
+	if (!bcm_platform_data_avail)
+		panic("platform data not available");
+
+	return (&bcm_platform_data);
+}
+
+/* Default (no-op) bcm_find_core() implementation. */
+int
+bcm_find_core_default(struct bhnd_chipid *chipid, bhnd_devclass_t devclass,
+    int unit, struct bhnd_core_info *info, uintptr_t *addr)
+{
+	return (ENODEV);
+}
+
+/**
+ * Search @p chipid's enumeration table for a core with @p devclass and
+ * @p unit.
+ * 
+ * @param	chipid		Chip identification data, including the address
+ *				of the enumeration table to be searched.
+ * @param	devclass	Search for a core matching this device class.
+ * @param	unit		The core's required unit number.
+ * @param[out]	info		On success, will be populated with the core
+ *				info.
+ */
+static int
+bcm_find_core(struct bhnd_chipid *chipid, bhnd_devclass_t devclass, int unit,
+    struct bhnd_core_info *info, uintptr_t *addr)
+{
+	switch (chipid->chip_type) {
+	case BHND_CHIPTYPE_SIBA:
+		return (bcm_find_core_siba(chipid, devclass, unit, info, addr));
+		break;
+	default:
+		if (!BHND_CHIPTYPE_HAS_EROM(chipid->chip_type)) {
+			printf("%s: unsupported chip type: %d\n", __FUNCTION__,
+			    chipid->chip_type);
+			return (ENXIO);
+		}
+		return (bcm_find_core_bcma(chipid, devclass, unit, info, addr));
+	}
+}
+
+/**
+ * Populate platform configuration data.
+ */
+static int
+bcm_init_platform_data(struct bcm_platform *pdata)
+{
+	uint32_t		reg;
+	bhnd_addr_t		enum_addr;
+	long			maddr;
+	uint8_t			chip_type;
+	bool			aob, pmu;
+	int			error;
+
+	/* Fetch CFE console handle (if any). Must be initialized before
+	 * any calls to printf/early_putc. */
+#ifdef CFE
+	if ((pdata->cfe_console = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0)
+		pdata->cfe_console = -1;
+#endif
+
+	/* Fetch bhnd/chipc address */ 
+	if (resource_long_value("bhnd", 0, "maddr", &maddr) == 0)
+		pdata->cc_addr = (u_long)maddr;
+	else
+		pdata->cc_addr = BHND_DEFAULT_CHIPC_ADDR;
+
+	/* Read chip identifier from ChipCommon */
+	reg = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_ID);
+	chip_type = CHIPC_GET_BITS(reg, CHIPC_ID_BUS);
+
+	if (BHND_CHIPTYPE_HAS_EROM(chip_type))
+		enum_addr = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_EROMPTR);
+	else
+		enum_addr = pdata->cc_addr;
+
+	pdata->id = bhnd_parse_chipid(reg, enum_addr);
+
+	/* Fetch chipc core info and capabilities */
+	pdata->cc_caps = BCM_SOC_READ_4(pdata->cc_addr, CHIPC_CAPABILITIES);
+
+	error = bcm_find_core(&pdata->id, BHND_DEVCLASS_CC, 0, &pdata->cc_id,
+	    NULL);
+	if (error) {
+		printf("%s: error locating chipc core: %d", __FUNCTION__,
+		    error);
+		return (error);
+	}
+
+	if (CHIPC_HWREV_HAS_CAP_EXT(pdata->cc_id.hwrev)) {
+		pdata->cc_caps_ext = BCM_SOC_READ_4(pdata->cc_addr,
+		    CHIPC_CAPABILITIES_EXT);
+	} else {
+		pdata->cc_caps_ext = 0x0;	
+	}
+
+	/* Fetch PMU info */
+	pmu = CHIPC_GET_FLAG(pdata->cc_caps, CHIPC_CAP_PMU);
+	aob = CHIPC_GET_FLAG(pdata->cc_caps_ext, CHIPC_CAP2_AOB);
+
+	if (pmu && aob) {
+		/* PMU block mapped to a PMU core on the Always-on-Bus (aob) */
+		error = bcm_find_core(&pdata->id, BHND_DEVCLASS_PMU, 0,
+		    &pdata->pmu_id,  &pdata->pmu_addr);
+
+		if (error) {
+			printf("%s: error locating pmu core: %d", __FUNCTION__,
+			    error);
+			return (error);
+		}
+	} else if (pmu) {
+		/* PMU block mapped to chipc */
+		pdata->pmu_addr = pdata->cc_addr;
+		pdata->pmu_id = pdata->cc_id;
+	} else {
+		/* No PMU */
+		pdata->pmu_addr = 0x0;
+		memset(&pdata->pmu_id, 0, sizeof(pdata->pmu_id));
+	}
+
+	bcm_platform_data_avail = true;
+	return (0);
+}
 
 void
 platform_cpu_init()
@@ -162,23 +317,42 @@ mips_init(void)
 void
 platform_reset(void)
 {
+	bool bcm4785war;
+
 	printf("bcm::platform_reset()\n");
 	intr_disable();
 
-#if defined(CFE)
-	cfe_exit(0, 0);
-#else
-	/* PMU watchdog reset */
-	BCM_WRITE_REG32(BCM_REG_CHIPC_PMUWD_OFFS, 2); /* PMU watchdog */
+#ifdef CFE
+	/* Fall back on CFE if reset requested during platform
+	 * data initialization */
+	if (!bcm_platform_data_avail) {
+		cfe_exit(0, 0);
+		while (1);
+	}
 #endif
 
-#if 0
-	/* Non-PMU reset 
-	 * XXX: Need chipc capability flags */
-	*((volatile uint8_t *)MIPS_PHYS_TO_KSEG1(SENTRY5_EXTIFADR)) = 0x80;
-#endif
-	
-	for (;;);
+	/* Handle BCM4785-specific behavior */
+	bcm4785war = false;
+	if (bcm_get_platform()->id.chip_id == BHND_CHIPID_BCM4785) {
+		bcm4785war = true;
+
+		/* Switch to async mode */
+		bcm_mips_wr_pllcfg3(MIPS_BCMCFG_PLLCFG3_SM);
+	}
+
+	/* Set watchdog (PMU or ChipCommon) */
+	if (bcm_get_platform()->pmu_addr != 0x0) {
+		BCM_CHIPC_WRITE_4(CHIPC_PMU_WATCHDOG, 1);
+	} else
+		BCM_CHIPC_WRITE_4(CHIPC_WATCHDOG, 1);
+
+	/* BCM4785 */
+	if (bcm4785war) {
+		mips_sync();
+		__asm __volatile("wait");
+	}
+
+	while (1);
 }
 
 void
@@ -188,6 +362,7 @@ platform_start(__register_t a0, __regist
 	vm_offset_t 		 kernend;
 	uint64_t		 platform_counter_freq;
 	struct bcm_socinfo	*socinfo;
+	int			 error;
 
 	/* clear the BSS and SBSS segments */
 	kernend = (vm_offset_t)&end;
@@ -213,36 +388,9 @@ platform_start(__register_t a0, __regist
 		cfe_init(a0, a2);
 #endif
 
-#if 0
-	/*
-	 * Probe the Broadcom on-chip PLL clock registers
-	 * and discover the CPU pipeline clock and bus clock
-	 * multipliers from this.
-	 * XXX: Wrong place. You have to ask the ChipCommon
-	 * or External Interface cores on the SiBa.
-	 */
-	uint32_t busmult, cpumult, refclock, clkcfg1;
-#define S5_CLKCFG1_REFCLOCK_MASK	0x0000001F
-#define S5_CLKCFG1_BUSMULT_MASK		0x000003E0
-#define S5_CLKCFG1_BUSMULT_SHIFT	5
-#define S5_CLKCFG1_CPUMULT_MASK		0xFFFFFC00
-#define S5_CLKCFG1_CPUMULT_SHIFT	10
-
-	counter_freq = 100000000;	/* XXX */
-
-	clkcfg1 = s5_rd_clkcfg1();
-	printf("clkcfg1 = 0x%08x\n", clkcfg1);
-
-	refclock = clkcfg1 & 0x1F;
-	busmult = ((clkcfg1 & 0x000003E0) >> 5) + 1;
-	cpumult = ((clkcfg1 & 0xFFFFFC00) >> 10) + 1;
-
-	printf("refclock = %u\n", refclock);
-	printf("busmult = %u\n", busmult);
-	printf("cpumult = %u\n", cpumult);
-
-	counter_freq = cpumult * refclock;
-#endif
+	/* Init BCM platform data */
+	if ((error = bcm_init_platform_data(&bcm_platform_data)))
+		panic("bcm_init_platform_data() failed: %d", error);
 
 	socinfo = bcm_get_socinfo();
 	platform_counter_freq = socinfo->cpurate * 1000 * 1000; /* BCM4718 is 480MHz */
@@ -267,20 +415,20 @@ platform_start(__register_t a0, __regist
 static void
 bcm_cfe_eputc(int c)
 {
-	static int	fd = -1;
 	unsigned char	ch;
+	int		handle;
 
 	ch = (unsigned char) c;
 
-	if (fd == -1) {
-		if ((fd = cfe_getstdhandle(CFE_STDHANDLE_CONSOLE)) < 0)
-			return;
-	}
+	/* bcm_get_platform() cannot be used here, as we may be called
+	 * from bcm_init_platform_data(). */
+	if ((handle = bcm_platform_data.cfe_console) < 0)
+		return;
 
 	if (ch == '\n')
 		early_putc('\r');
 
-	while ((cfe_write(fd, &ch, 1)) == 0)
+	while ((cfe_write(handle, &ch, 1)) == 0)
 		continue;
 }
 

Added: head/sys/mips/broadcom/bcm_machdep.h
==============================================================================
--- /dev/null	00:00:00 1970	(empty, because file is newly added)
+++ head/sys/mips/broadcom/bcm_machdep.h	Fri Aug 26 20:16:02 2016	(r304859)
@@ -0,0 +1,93 @@
+/*-
+ * Copyright (c) 2016 Landon Fuller <landonf at FreeBSD.org>
+ * All rights reserved.
+ *
+ * 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,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ *
+ * NO WARRANTY
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ * 
+ * $FreeBSD$
+ */
+
+#ifndef	_MIPS_BROADCOM_BCM_MACHDEP_H_
+#define	_MIPS_BROADCOM_BCM_MACHDEP_H_
+
+#include <machine/cpufunc.h>
+#include <machine/cpuregs.h>
+
+#include <dev/bhnd/bhnd.h>
+
+struct bcm_platform {
+	struct bhnd_chipid	id;		/**< chip id */
+	struct bhnd_core_info	cc_id;		/**< chipc core info */
+	uintptr_t		cc_addr;	/**< chipc core phys address */
+	uint32_t		cc_caps;	/**< chipc capabilities */
+	uint32_t		cc_caps_ext;	/**< chipc extended capabilies */
+
+	/* On non-AOB devices, the PMU register block is mapped to chipc;
+	 * the pmu_id and pmu_addr values will be copied from cc_id
+	 * and cc_addr. */
+	struct bhnd_core_info	pmu_id;		/**< PMU core info */
+	uintptr_t		pmu_addr;	/**< PMU core phys address. */
+
+#ifdef CFE
+	int			cfe_console;	/**< Console handle, or -1 */
+#endif
+};
+
+

*** DIFF OUTPUT TRUNCATED AT 1000 LINES ***


More information about the svn-src-all mailing list