Index: projects/clang390-import/bin/dd/dd.c =================================================================== --- projects/clang390-import/bin/dd/dd.c (revision 308867) +++ projects/clang390-import/bin/dd/dd.c (revision 308868) @@ -1,586 +1,556 @@ /*- * Copyright (c) 1991, 1993, 1994 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Keith Muller of the University of California, San Diego and Lance * Visser of Convex Computer Corporation. * * 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. */ #if 0 #ifndef lint static char const copyright[] = "@(#) Copyright (c) 1991, 1993, 1994\n\ The Regents of the University of California. All rights reserved.\n"; #endif /* not lint */ #ifndef lint static char sccsid[] = "@(#)dd.c 8.5 (Berkeley) 4/2/94"; #endif /* not lint */ #endif #include __FBSDID("$FreeBSD$"); #include #include #include -#include #include #include -#include #include -#include #include #include #include #include #include #include #include #include #include #include #include #include "dd.h" #include "extern.h" static void dd_close(void); static void dd_in(void); static void getfdtype(IO *); static void setup(void); IO in, out; /* input/output state */ STAT st; /* statistics */ void (*cfunc)(void); /* conversion function */ uintmax_t cpy_cnt; /* # of blocks to copy */ static off_t pending = 0; /* pending seek if sparse */ u_int ddflags = 0; /* conversion options */ size_t cbsz; /* conversion block size */ uintmax_t files_cnt = 1; /* # of files to copy */ const u_char *ctab; /* conversion table */ char fill_char; /* Character to fill with if defined */ size_t speed = 0; /* maximum speed, in bytes per second */ volatile sig_atomic_t need_summary; int main(int argc __unused, char *argv[]) { (void)setlocale(LC_CTYPE, ""); jcl(argv); setup(); - caph_cache_catpages(); - if (cap_enter() == -1 && errno != ENOSYS) - err(1, "unable to enter capability mode"); - (void)signal(SIGINFO, siginfo_handler); (void)signal(SIGINT, terminate); atexit(summary); while (files_cnt--) dd_in(); dd_close(); /* * Some devices such as cfi(4) may perform significant amounts * of work when a write descriptor is closed. Close the out * descriptor explicitly so that the summary handler (called * from an atexit() hook) includes this work. */ close(out.fd); exit(0); } static int parity(u_char c) { int i; i = c ^ (c >> 1) ^ (c >> 2) ^ (c >> 3) ^ (c >> 4) ^ (c >> 5) ^ (c >> 6) ^ (c >> 7); return (i & 1); } static void setup(void) { u_int cnt; - cap_rights_t rights; - unsigned long cmds[] = { FIODTYPE, MTIOCTOP }; if (in.name == NULL) { in.name = "stdin"; in.fd = STDIN_FILENO; } else { in.fd = open(in.name, O_RDONLY, 0); if (in.fd == -1) err(1, "%s", in.name); - if (caph_limit_stdin() == -1) - err(1, "unable to limit capability rights"); } getfdtype(&in); - cap_rights_init(&rights, CAP_READ, CAP_SEEK); - if (cap_rights_limit(in.fd, &rights) == -1 && errno != ENOSYS) - err(1, "unable to limit capability rights"); - if (files_cnt > 1 && !(in.flags & ISTAPE)) errx(1, "files is not supported for non-tape devices"); - cap_rights_set(&rights, CAP_WRITE, CAP_FTRUNCATE, CAP_IOCTL); if (out.name == NULL) { /* No way to check for read access here. */ out.fd = STDOUT_FILENO; out.name = "stdout"; } else { #define OFLAGS \ (O_CREAT | (ddflags & (C_SEEK | C_NOTRUNC) ? 0 : O_TRUNC)) out.fd = open(out.name, O_RDWR | OFLAGS, DEFFILEMODE); /* * May not have read access, so try again with write only. * Without read we may have a problem if output also does * not support seeks. */ if (out.fd == -1) { out.fd = open(out.name, O_WRONLY | OFLAGS, DEFFILEMODE); out.flags |= NOREAD; - cap_rights_clear(&rights, CAP_READ); } if (out.fd == -1) err(1, "%s", out.name); - if (caph_limit_stdout() == -1) - err(1, "unable to limit capability rights"); } getfdtype(&out); - - if (cap_rights_limit(out.fd, &rights) == -1 && errno != ENOSYS) - err(1, "unable to limit capability rights"); - if (cap_ioctls_limit(out.fd, cmds, nitems(cmds)) == -1 && - errno != ENOSYS) - err(1, "unable to limit capability rights"); - - if (in.fd != STDERR_FILENO && out.fd != STDERR_FILENO) { - if (caph_limit_stderr() == -1) - err(1, "unable to limit capability rights"); - } /* * Allocate space for the input and output buffers. If not doing * record oriented I/O, only need a single buffer. */ if (!(ddflags & (C_BLOCK | C_UNBLOCK))) { if ((in.db = malloc(out.dbsz + in.dbsz - 1)) == NULL) err(1, "input buffer"); out.db = in.db; } else if ((in.db = malloc(MAX(in.dbsz, cbsz) + cbsz)) == NULL || (out.db = malloc(out.dbsz + cbsz)) == NULL) err(1, "output buffer"); /* dbp is the first free position in each buffer. */ in.dbp = in.db; out.dbp = out.db; /* Position the input/output streams. */ if (in.offset) pos_in(); if (out.offset) pos_out(); /* * Truncate the output file. If it fails on a type of output file * that it should _not_ fail on, error out. */ if ((ddflags & (C_OF | C_SEEK | C_NOTRUNC)) == (C_OF | C_SEEK) && out.flags & ISTRUNC) if (ftruncate(out.fd, out.offset * out.dbsz) == -1) err(1, "truncating %s", out.name); if (ddflags & (C_LCASE | C_UCASE | C_ASCII | C_EBCDIC | C_PARITY)) { if (ctab != NULL) { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = ctab[cnt]; } else { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = cnt; } if ((ddflags & C_PARITY) && !(ddflags & C_ASCII)) { /* * If the input is not EBCDIC, and we do parity * processing, strip input parity. */ for (cnt = 200; cnt <= 0377; ++cnt) casetab[cnt] = casetab[cnt & 0x7f]; } if (ddflags & C_LCASE) { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = tolower(casetab[cnt]); } else if (ddflags & C_UCASE) { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = toupper(casetab[cnt]); } if ((ddflags & C_PARITY)) { /* * This should strictly speaking be a no-op, but I * wonder what funny LANG settings could get us. */ for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = casetab[cnt] & 0x7f; } if ((ddflags & C_PARSET)) { for (cnt = 0; cnt <= 0377; ++cnt) casetab[cnt] = casetab[cnt] | 0x80; } if ((ddflags & C_PAREVEN)) { for (cnt = 0; cnt <= 0377; ++cnt) if (parity(casetab[cnt])) casetab[cnt] = casetab[cnt] | 0x80; } if ((ddflags & C_PARODD)) { for (cnt = 0; cnt <= 0377; ++cnt) if (!parity(casetab[cnt])) casetab[cnt] = casetab[cnt] | 0x80; } ctab = casetab; } if (clock_gettime(CLOCK_MONOTONIC, &st.start)) err(1, "clock_gettime"); } static void getfdtype(IO *io) { struct stat sb; int type; if (fstat(io->fd, &sb) == -1) err(1, "%s", io->name); if (S_ISREG(sb.st_mode)) io->flags |= ISTRUNC; if (S_ISCHR(sb.st_mode) || S_ISBLK(sb.st_mode)) { if (ioctl(io->fd, FIODTYPE, &type) == -1) { err(1, "%s", io->name); } else { if (type & D_TAPE) io->flags |= ISTAPE; else if (type & (D_DISK | D_MEM)) io->flags |= ISSEEK; if (S_ISCHR(sb.st_mode) && (type & D_TAPE) == 0) io->flags |= ISCHR; } return; } errno = 0; if (lseek(io->fd, (off_t)0, SEEK_CUR) == -1 && errno == ESPIPE) io->flags |= ISPIPE; else io->flags |= ISSEEK; } /* * Limit the speed by adding a delay before every block read. * The delay (t_usleep) is equal to the time computed from block * size and the specified speed limit (t_target) minus the time * spent on actual read and write operations (t_io). */ static void speed_limit(void) { static double t_prev, t_usleep; double t_now, t_io, t_target; t_now = secs_elapsed(); t_io = t_now - t_prev - t_usleep; t_target = (double)in.dbsz / (double)speed; t_usleep = t_target - t_io; if (t_usleep > 0) usleep(t_usleep * 1000000); else t_usleep = 0; t_prev = t_now; } static void dd_in(void) { ssize_t n; for (;;) { switch (cpy_cnt) { case -1: /* count=0 was specified */ return; case 0: break; default: if (st.in_full + st.in_part >= (uintmax_t)cpy_cnt) return; break; } if (speed > 0) speed_limit(); /* * Zero the buffer first if sync; if doing block operations, * use spaces. */ if (ddflags & C_SYNC) { if (ddflags & C_FILL) memset(in.dbp, fill_char, in.dbsz); else if (ddflags & (C_BLOCK | C_UNBLOCK)) memset(in.dbp, ' ', in.dbsz); else memset(in.dbp, 0, in.dbsz); } n = read(in.fd, in.dbp, in.dbsz); if (n == 0) { in.dbrcnt = 0; return; } /* Read error. */ if (n == -1) { /* * If noerror not specified, die. POSIX requires that * the warning message be followed by an I/O display. */ if (!(ddflags & C_NOERROR)) err(1, "%s", in.name); warn("%s", in.name); summary(); /* * If it's a seekable file descriptor, seek past the * error. If your OS doesn't do the right thing for * raw disks this section should be modified to re-read * in sector size chunks. */ if (in.flags & ISSEEK && lseek(in.fd, (off_t)in.dbsz, SEEK_CUR)) warn("%s", in.name); /* If sync not specified, omit block and continue. */ if (!(ddflags & C_SYNC)) continue; /* Read errors count as full blocks. */ in.dbcnt += in.dbrcnt = in.dbsz; ++st.in_full; /* Handle full input blocks. */ } else if ((size_t)n == in.dbsz) { in.dbcnt += in.dbrcnt = n; ++st.in_full; /* Handle partial input blocks. */ } else { /* If sync, use the entire block. */ if (ddflags & C_SYNC) in.dbcnt += in.dbrcnt = in.dbsz; else in.dbcnt += in.dbrcnt = n; ++st.in_part; } /* * POSIX states that if bs is set and no other conversions * than noerror, notrunc or sync are specified, the block * is output without buffering as it is read. */ if ((ddflags & ~(C_NOERROR | C_NOTRUNC | C_SYNC)) == C_BS) { out.dbcnt = in.dbcnt; dd_out(1); in.dbcnt = 0; continue; } if (ddflags & C_SWAB) { if ((n = in.dbrcnt) & 1) { ++st.swab; --n; } swab(in.dbp, in.dbp, (size_t)n); } in.dbp += in.dbrcnt; (*cfunc)(); if (need_summary) { summary(); } } } /* * Clean up any remaining I/O and flush output. If necessary, the output file * is truncated. */ static void dd_close(void) { if (cfunc == def) def_close(); else if (cfunc == block) block_close(); else if (cfunc == unblock) unblock_close(); if (ddflags & C_OSYNC && out.dbcnt && out.dbcnt < out.dbsz) { if (ddflags & C_FILL) memset(out.dbp, fill_char, out.dbsz - out.dbcnt); else if (ddflags & (C_BLOCK | C_UNBLOCK)) memset(out.dbp, ' ', out.dbsz - out.dbcnt); else memset(out.dbp, 0, out.dbsz - out.dbcnt); out.dbcnt = out.dbsz; } if (out.dbcnt || pending) dd_out(1); /* * If the file ends with a hole, ftruncate it to extend its size * up to the end of the hole (without having to write any data). */ if (out.seek_offset > 0 && (out.flags & ISTRUNC)) { if (ftruncate(out.fd, out.seek_offset) == -1) err(1, "truncating %s", out.name); } } void dd_out(int force) { u_char *outp; size_t cnt, i, n; ssize_t nw; static int warned; int sparse; /* * Write one or more blocks out. The common case is writing a full * output block in a single write; increment the full block stats. * Otherwise, we're into partial block writes. If a partial write, * and it's a character device, just warn. If a tape device, quit. * * The partial writes represent two cases. 1: Where the input block * was less than expected so the output block was less than expected. * 2: Where the input block was the right size but we were forced to * write the block in multiple chunks. The original versions of dd(1) * never wrote a block in more than a single write, so the latter case * never happened. * * One special case is if we're forced to do the write -- in that case * we play games with the buffer size, and it's usually a partial write. */ outp = out.db; /* * If force, first try to write all pending data, else try to write * just one block. Subsequently always write data one full block at * a time at most. */ for (n = force ? out.dbcnt : out.dbsz;; n = out.dbsz) { cnt = n; do { sparse = 0; if (ddflags & C_SPARSE) { sparse = 1; /* Is buffer sparse? */ for (i = 0; i < cnt; i++) if (outp[i] != 0) { sparse = 0; break; } } if (sparse && !force) { pending += cnt; nw = cnt; } else { if (pending != 0) { /* * Seek past hole. Note that we need to record the * reached offset, because we might have no more data * to write, in which case we'll need to call * ftruncate to extend the file size. */ out.seek_offset = lseek(out.fd, pending, SEEK_CUR); if (out.seek_offset == -1) err(2, "%s: seek error creating sparse file", out.name); pending = 0; } if (cnt) { nw = write(out.fd, outp, cnt); out.seek_offset = 0; } else { return; } } if (nw <= 0) { if (nw == 0) errx(1, "%s: end of device", out.name); if (errno != EINTR) err(1, "%s", out.name); nw = 0; } outp += nw; st.bytes += nw; if ((size_t)nw == n && n == out.dbsz) ++st.out_full; else ++st.out_part; if ((size_t) nw != cnt) { if (out.flags & ISTAPE) errx(1, "%s: short write on tape device", out.name); if (out.flags & ISCHR && !warned) { warned = 1; warnx("%s: short write on character device", out.name); } } cnt -= nw; } while (cnt != 0); if ((out.dbcnt -= n) < out.dbsz) break; } /* Reassemble the output block. */ if (out.dbcnt) (void)memmove(out.db, out.dbp - out.dbcnt, out.dbcnt); out.dbp = out.db + out.dbcnt; } Index: projects/clang390-import/sbin/nvmecontrol/logpage.c =================================================================== --- projects/clang390-import/sbin/nvmecontrol/logpage.c (revision 308867) +++ projects/clang390-import/sbin/nvmecontrol/logpage.c (revision 308868) @@ -1,358 +1,915 @@ /*- * Copyright (c) 2013 EMC Corp. * All rights reserved. * * Copyright (C) 2012-2013 Intel Corporation * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #include #include #include #include #include +#include +#if _BYTE_ORDER != _LITTLE_ENDIAN +#error "Code only works on little endian machines" +#endif + #include "nvmecontrol.h" #define DEFAULT_SIZE (4096) #define MAX_FW_SLOTS (7) typedef void (*print_fn_t)(void *buf, uint32_t size); +struct kv_name +{ + uint32_t key; + const char *name; +}; + +static const char * +kv_lookup(const struct kv_name *kv, size_t kv_count, uint32_t key) +{ + static char bad[32]; + size_t i; + + for (i = 0; i < kv_count; i++, kv++) + if (kv->key == key) + return kv->name; + snprintf(bad, sizeof(bad), "Attribute %#x", key); + return bad; +} + +/* + * 128-bit integer augments to standard values + */ +#define UINT128_DIG 39 +typedef __uint128_t uint128_t; + +static inline uint128_t +to128(void *p) +{ + return *(uint128_t *)p; +} + +static char * +uint128_to_str(uint128_t u, char *buf, size_t buflen) +{ + char *end = buf + buflen - 1; + + *end-- = '\0'; + if (u == 0) + *end-- = '0'; + while (u && end >= buf) { + *end-- = u % 10 + '0'; + u /= 10; + } + end++; + if (u != 0) + return NULL; + + return end; +} + +/* "fMissing" from endian.h */ +static __inline uint64_t +le48dec(const void *pp) +{ + uint8_t const *p = (uint8_t const *)pp; + + return (((uint64_t)le16dec(p + 4) << 32) | le32dec(p)); +} + static void * get_log_buffer(uint32_t size) { void *buf; if ((buf = malloc(size)) == NULL) errx(1, "unable to malloc %u bytes", size); memset(buf, 0, size); return (buf); } void -read_logpage(int fd, uint8_t log_page, int nsid, void *payload, +read_logpage(int fd, uint8_t log_page, int nsid, void *payload, uint32_t payload_size) { struct nvme_pt_command pt; memset(&pt, 0, sizeof(pt)); pt.cmd.opc = NVME_OPC_GET_LOG_PAGE; pt.cmd.nsid = nsid; pt.cmd.cdw10 = ((payload_size/sizeof(uint32_t)) - 1) << 16; pt.cmd.cdw10 |= log_page; pt.buf = payload; pt.len = payload_size; pt.is_read = 1; if (ioctl(fd, NVME_PASSTHROUGH_CMD, &pt) < 0) err(1, "get log page request failed"); if (nvme_completion_is_error(&pt.cpl)) errx(1, "get log page request returned error"); } static void print_log_error(void *buf, uint32_t size) { int i, nentries; struct nvme_error_information_entry *entry = buf; struct nvme_status *status; printf("Error Information Log\n"); printf("=====================\n"); if (entry->error_count == 0) { printf("No error entries found\n"); return; } nentries = size/sizeof(struct nvme_error_information_entry); for (i = 0; i < nentries; i++, entry++) { if (entry->error_count == 0) break; status = &entry->status; printf("Entry %02d\n", i + 1); printf("=========\n"); printf(" Error count: %ju\n", entry->error_count); printf(" Submission queue ID: %u\n", entry->sqid); printf(" Command ID: %u\n", entry->cid); /* TODO: Export nvme_status_string structures from kernel? */ printf(" Status:\n"); printf(" Phase tag: %d\n", status->p); printf(" Status code: %d\n", status->sc); printf(" Status code type: %d\n", status->sct); printf(" More: %d\n", status->m); printf(" DNR: %d\n", status->dnr); printf(" Error location: %u\n", entry->error_location); printf(" LBA: %ju\n", entry->lba); printf(" Namespace ID: %u\n", entry->nsid); printf(" Vendor specific info: %u\n", entry->vendor_specific); } } static void +print_temp(uint16_t t) +{ + printf("%u K, %2.2f C, %3.2f F\n", t, (float)t - 273.15, (float)t * 9 / 5 - 459.67); +} + + +static void print_log_health(void *buf, uint32_t size __unused) { struct nvme_health_information_page *health = buf; + char cbuf[UINT128_DIG + 1]; + int i; printf("SMART/Health Information Log\n"); printf("============================\n"); printf("Critical Warning State: 0x%02x\n", health->critical_warning.raw); printf(" Available spare: %d\n", health->critical_warning.bits.available_spare); printf(" Temperature: %d\n", health->critical_warning.bits.temperature); printf(" Device reliability: %d\n", health->critical_warning.bits.device_reliability); printf(" Read only: %d\n", health->critical_warning.bits.read_only); printf(" Volatile memory backup: %d\n", health->critical_warning.bits.volatile_memory_backup); - printf("Temperature: %u K, %2.2f C, %3.2f F\n", - health->temperature, - (float)health->temperature - (float)273.15, - ((float)health->temperature * (float)9/5) - (float)459.67); + printf("Temperature: "); + print_temp(health->temperature); printf("Available spare: %u\n", health->available_spare); printf("Available spare threshold: %u\n", health->available_spare_threshold); printf("Percentage used: %u\n", health->percentage_used); - /* - * TODO: These are pretty ugly in hex. Is there a library that - * will convert 128-bit unsigned values to decimal? - */ - printf("Data units (512 byte) read: 0x%016jx%016jx\n", - health->data_units_read[1], - health->data_units_read[0]); - printf("Data units (512 byte) written: 0x%016jx%016jx\n", - health->data_units_written[1], - health->data_units_written[0]); - printf("Host read commands: 0x%016jx%016jx\n", - health->host_read_commands[1], - health->host_read_commands[0]); - printf("Host write commands: 0x%016jx%016jx\n", - health->host_write_commands[1], - health->host_write_commands[0]); - printf("Controller busy time (minutes): 0x%016jx%016jx\n", - health->controller_busy_time[1], - health->controller_busy_time[0]); - printf("Power cycles: 0x%016jx%016jx\n", - health->power_cycles[1], - health->power_cycles[0]); - printf("Power on hours: 0x%016jx%016jx\n", - health->power_on_hours[1], - health->power_on_hours[0]); - printf("Unsafe shutdowns: 0x%016jx%016jx\n", - health->unsafe_shutdowns[1], - health->unsafe_shutdowns[0]); - printf("Media errors: 0x%016jx%016jx\n", - health->media_errors[1], - health->media_errors[0]); - printf("No. error info log entries: 0x%016jx%016jx\n", - health->num_error_info_log_entries[1], - health->num_error_info_log_entries[0]); + printf("Data units (512,000 byte) read: %s\n", + uint128_to_str(to128(health->data_units_read), cbuf, sizeof(cbuf))); + printf("Data units written: %s\n", + uint128_to_str(to128(health->data_units_written), cbuf, sizeof(cbuf))); + printf("Host read commands: %s\n", + uint128_to_str(to128(health->host_read_commands), cbuf, sizeof(cbuf))); + printf("Host write commands: %s\n", + uint128_to_str(to128(health->host_write_commands), cbuf, sizeof(cbuf))); + printf("Controller busy time (minutes): %s\n", + uint128_to_str(to128(health->controller_busy_time), cbuf, sizeof(cbuf))); + printf("Power cycles: %s\n", + uint128_to_str(to128(health->power_cycles), cbuf, sizeof(cbuf))); + printf("Power on hours: %s\n", + uint128_to_str(to128(health->power_on_hours), cbuf, sizeof(cbuf))); + printf("Unsafe shutdowns: %s\n", + uint128_to_str(to128(health->unsafe_shutdowns), cbuf, sizeof(cbuf))); + printf("Media errors: %s\n", + uint128_to_str(to128(health->media_errors), cbuf, sizeof(cbuf))); + printf("No. error info log entries: %s\n", + uint128_to_str(to128(health->num_error_info_log_entries), cbuf, sizeof(cbuf))); + + printf("Warning Temp Composite Time: %d\n", health->warning_temp_time); + printf("Error Temp Composite Time: %d\n", health->error_temp_time); + for (i = 0; i < 7; i++) { + if (health->temp_sensor[i] == 0) + continue; + printf("Temperature Sensor %d: ", i + 1); + print_temp(health->temp_sensor[i]); + } } static void print_log_firmware(void *buf, uint32_t size __unused) { int i; const char *status; struct nvme_firmware_page *fw = buf; printf("Firmware Slot Log\n"); printf("=================\n"); for (i = 0; i < MAX_FW_SLOTS; i++) { printf("Slot %d: ", i + 1); if (fw->afi.slot == i + 1) status = " Active"; else status = "Inactive"; if (fw->revision[i] == 0LLU) printf("Empty\n"); else if (isprint(*(char *)&fw->revision[i])) printf("[%s] %.8s\n", status, (char *)&fw->revision[i]); else printf("[%s] %016jx\n", status, fw->revision[i]); } } +/* + * Intel specific log pages from + * http://www.intel.com/content/dam/www/public/us/en/documents/product-specifications/ssd-dc-p3700-spec.pdf + * + * Though the version as of this date has a typo for the size of log page 0xca, + * offset 147: it is only 1 byte, not 6. + */ +static void +print_intel_temp_stats(void *buf, uint32_t size __unused) +{ + struct intel_log_temp_stats *temp = buf; + + printf("Intel Temperature Log\n"); + printf("=====================\n"); + + printf("Current: "); + print_temp(temp->current); + printf("Overtemp Last Flags %#jx\n", (uintmax_t)temp->overtemp_flag_last); + printf("Overtemp Lifetime Flags %#jx\n", (uintmax_t)temp->overtemp_flag_life); + printf("Max Temperature "); + print_temp(temp->max_temp); + printf("Min Temperature "); + print_temp(temp->min_temp); + printf("Max Operating Temperature "); + print_temp(temp->max_oper_temp); + printf("Min Operating Temperature "); + print_temp(temp->min_oper_temp); + printf("Estimated Temperature Offset: %ju C/K\n", (uintmax_t)temp->est_offset); +} + +static void +print_intel_add_smart(void *buf, uint32_t size __unused) +{ + uint8_t *walker = buf; + uint8_t *end = walker + 150; + const char *name; + uint64_t raw; + uint8_t normalized; + + static struct kv_name kv[] = + { + { 0xab, "Program Fail Count" }, + { 0xac, "Erase Fail Count" }, + { 0xad, "Wear Leveling Count" }, + { 0xb8, "End to End Error Count" }, + { 0xc7, "CRC Error Count" }, + { 0xe2, "Timed: Media Wear" }, + { 0xe3, "Timed: Host Read %" }, + { 0xe4, "Timed: Elapsed Time" }, + { 0xea, "Thermal Throttle Status" }, + { 0xf0, "Retry Buffer Overflows" }, + { 0xf3, "PLL Lock Loss Count" }, + { 0xf4, "NAND Bytes Written" }, + { 0xf5, "Host Bytes Written" }, + }; + + printf("Additional SMART Data Log\n"); + printf("=========================\n"); + /* + * walker[0] = Key + * walker[1,2] = reserved + * walker[3] = Normalized Value + * walker[4] = reserved + * walker[5..10] = Little Endian Raw value + * (or other represenations) + * walker[11] = reserved + */ + while (walker < end) { + name = kv_lookup(kv, nitems(kv), *walker); + normalized = walker[3]; + raw = le48dec(walker + 5); + switch (*walker){ + case 0: + break; + case 0xad: + printf("%-32s: %3d min: %u max: %u ave: %u\n", name, normalized, + le16dec(walker + 5), le16dec(walker + 7), le16dec(walker + 9)); + break; + case 0xe2: + printf("%-32s: %3d %.3f%%\n", name, normalized, raw / 1024.0); + break; + case 0xea: + printf("%-32s: %3d %d%% %d times\n", name, normalized, walker[5], le32dec(walker+6)); + break; + default: + printf("%-32s: %3d %ju\n", name, normalized, (uintmax_t)raw); + break; + } + walker += 12; + } +} + +/* + * HGST's 0xc1 page. This is a grab bag of additional data. Please see + * https://www.hgst.com/sites/default/files/resources/US_SN150_ProdManual.pdf + * https://www.hgst.com/sites/default/files/resources/US_SN100_ProdManual.pdf + * Appendix A for details + */ + +typedef void (*subprint_fn_t)(void *buf, uint16_t subtype, uint8_t res, uint32_t size); + +struct subpage_print +{ + uint16_t key; + subprint_fn_t fn; +}; + +static void print_hgst_info_write_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); +static void print_hgst_info_read_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); +static void print_hgst_info_verify_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); +static void print_hgst_info_self_test(void *buf, uint16_t subtype, uint8_t res, uint32_t size); +static void print_hgst_info_background_scan(void *buf, uint16_t subtype, uint8_t res, uint32_t size); +static void print_hgst_info_erase_errors(void *buf, uint16_t subtype, uint8_t res, uint32_t size); +static void print_hgst_info_erase_counts(void *buf, uint16_t subtype, uint8_t res, uint32_t size); +static void print_hgst_info_temp_history(void *buf, uint16_t subtype, uint8_t res, uint32_t size); +static void print_hgst_info_ssd_perf(void *buf, uint16_t subtype, uint8_t res, uint32_t size); +static void print_hgst_info_firmware_load(void *buf, uint16_t subtype, uint8_t res, uint32_t size); + +static struct subpage_print hgst_subpage[] = { + { 0x02, print_hgst_info_write_errors }, + { 0x03, print_hgst_info_read_errors }, + { 0x05, print_hgst_info_verify_errors }, + { 0x10, print_hgst_info_self_test }, + { 0x15, print_hgst_info_background_scan }, + { 0x30, print_hgst_info_erase_errors }, + { 0x31, print_hgst_info_erase_counts }, + { 0x32, print_hgst_info_temp_history }, + { 0x37, print_hgst_info_ssd_perf }, + { 0x38, print_hgst_info_firmware_load }, +}; + +/* Print a subpage that is basically just key value pairs */ +static void +print_hgst_info_subpage_gen(void *buf, uint16_t subtype __unused, uint32_t size, + const struct kv_name *kv, size_t kv_count) +{ + uint8_t *wsp, *esp; + uint16_t ptype; + uint8_t plen; + uint64_t param; + int i; + + wsp = buf; + esp = wsp + size; + while (wsp < esp) { + ptype = le16dec(wsp); + wsp += 2; + wsp++; /* Flags, just ignore */ + plen = *wsp++; + param = 0; + for (i = 0; i < plen; i++) + param |= (uint64_t)*wsp++ << (i * 8); + printf(" %-30s: %jd\n", kv_lookup(kv, kv_count, ptype), (uintmax_t)param); + } +} + +static void +print_hgst_info_write_errors(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) +{ + static struct kv_name kv[] = + { + { 0x0000, "Corrected Without Delay" }, + { 0x0001, "Corrected Maybe Delayed" }, + { 0x0002, "Re-Writes" }, + { 0x0003, "Errors Corrected" }, + { 0x0004, "Correct Algorithm Used" }, + { 0x0005, "Bytes Processed" }, + { 0x0006, "Uncorrected Errors" }, + { 0x8000, "Flash Write Commands" }, + { 0x8001, "HGST Special" }, + }; + + printf("Write Errors Subpage:\n"); + print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); +} + +static void +print_hgst_info_read_errors(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) +{ + static struct kv_name kv[] = + { + { 0x0000, "Corrected Without Delay" }, + { 0x0001, "Corrected Maybe Delayed" }, + { 0x0002, "Re-Reads" }, + { 0x0003, "Errors Corrected" }, + { 0x0004, "Correct Algorithm Used" }, + { 0x0005, "Bytes Processed" }, + { 0x0006, "Uncorrected Errors" }, + { 0x8000, "Flash Read Commands" }, + { 0x8001, "XOR Recovered" }, + { 0x8002, "Total Corrected Bits" }, + }; + + printf("Read Errors Subpage:\n"); + print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); +} + +static void +print_hgst_info_verify_errors(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) +{ + static struct kv_name kv[] = + { + { 0x0000, "Corrected Without Delay" }, + { 0x0001, "Corrected Maybe Delayed" }, + { 0x0002, "Re-Reads" }, + { 0x0003, "Errors Corrected" }, + { 0x0004, "Correct Algorithm Used" }, + { 0x0005, "Bytes Processed" }, + { 0x0006, "Uncorrected Errors" }, + { 0x8000, "Commands Processed" }, + }; + + printf("Verify Errors Subpage:\n"); + print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); +} + +static void +print_hgst_info_self_test(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size) +{ + size_t i; + uint8_t *walker = buf; + uint16_t code, hrs; + uint32_t lba; + + printf("Self Test Subpage:\n"); + for (i = 0; i < size / 20; i++) { /* Each entry is 20 bytes */ + code = le16dec(walker); + walker += 2; + walker++; /* Ignore fixed flags */ + if (*walker == 0) /* Last entry is zero length */ + break; + if (*walker++ != 0x10) { + printf("Bad length for self test report\n"); + return; + } + printf(" %-30s: %d\n", "Recent Test", code); + printf(" %-28s: %#x\n", "Self-Test Results", *walker & 0xf); + printf(" %-28s: %#x\n", "Self-Test Code", (*walker >> 5) & 0x7); + walker++; + printf(" %-28s: %#x\n", "Self-Test Number", *walker++); + hrs = le16dec(walker); + walker += 2; + lba = le32dec(walker); + walker += 4; + printf(" %-28s: %u\n", "Total Power On Hrs", hrs); + printf(" %-28s: %#jx (%jd)\n", "LBA", (uintmax_t)lba, (uintmax_t)lba); + printf(" %-28s: %#x\n", "Sense Key", *walker++ & 0xf); + printf(" %-28s: %#x\n", "Additional Sense Code", *walker++); + printf(" %-28s: %#x\n", "Additional Sense Qualifier", *walker++); + printf(" %-28s: %#x\n", "Vendor Specific Detail", *walker++); + } +} + +static void +print_hgst_info_background_scan(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size) +{ + uint8_t *walker = buf; + uint8_t status; + uint16_t code, nscan, progress; + uint32_t pom, nand; + + printf("Background Media Scan Subpage:\n"); + /* Decode the header */ + code = le16dec(walker); + walker += 2; + walker++; /* Ignore fixed flags */ + if (*walker++ != 0x10) { + printf("Bad length for background scan header\n"); + return; + } + if (code != 0) { + printf("Expceted code 0, found code %#x\n", code); + return; + } + pom = le32dec(walker); + walker += 4; + walker++; /* Reserved */ + status = *walker++; + nscan = le16dec(walker); + walker += 2; + progress = le16dec(walker); + walker += 2; + walker += 6; /* Reserved */ + printf(" %-30s: %d\n", "Power On Minutes", pom); + printf(" %-30s: %x (%s)\n", "BMS Status", status, + status == 0 ? "idle" : (status == 1 ? "active" : (status == 8 ? "suspended" : "unknown"))); + printf(" %-30s: %d\n", "Number of BMS", nscan); + printf(" %-30s: %d\n", "Progress Current BMS", progress); + /* Report retirements */ + if (walker - (uint8_t *)buf != 20) { + printf("Coding error, offset not 20\n"); + return; + } + size -= 20; + printf(" %-30s: %d\n", "BMS retirements", size / 0x18); + while (size > 0) { + code = le16dec(walker); + walker += 2; + walker++; + if (*walker++ != 0x14) { + printf("Bad length parameter\n"); + return; + } + pom = le32dec(walker); + walker += 4; + /* + * Spec sheet says the following are hard coded, if true, just + * print the NAND retirement. + */ + if (walker[0] == 0x41 && + walker[1] == 0x0b && + walker[2] == 0x01 && + walker[3] == 0x00 && + walker[4] == 0x00 && + walker[5] == 0x00 && + walker[6] == 0x00 && + walker[7] == 0x00) { + walker += 8; + walker += 4; /* Skip reserved */ + nand = le32dec(walker); + walker += 4; + printf(" %-30s: %d\n", "Retirement number", code); + printf(" %-28s: %#x\n", "NAND (C/T)BBBPPP", nand); + } else { + printf("Parameter %#x entry corrupt\n", code); + walker += 16; + } + } +} + +static void +print_hgst_info_erase_errors(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size) +{ + static struct kv_name kv[] = + { + { 0x0000, "Corrected Without Delay" }, + { 0x0001, "Corrected Maybe Delayed" }, + { 0x0002, "Re-Erase" }, + { 0x0003, "Errors Corrected" }, + { 0x0004, "Correct Algorithm Used" }, + { 0x0005, "Bytes Processed" }, + { 0x0006, "Uncorrected Errors" }, + { 0x8000, "Flash Erase Commands" }, + { 0x8001, "Mfg Defect Count" }, + { 0x8002, "Grown Defect Count" }, + { 0x8003, "Erase Count -- User" }, + { 0x8004, "Erase Count -- System" }, + }; + + printf("Erase Errors Subpage:\n"); + print_hgst_info_subpage_gen(buf, subtype, size, kv, nitems(kv)); +} + +static void +print_hgst_info_erase_counts(void *buf, uint16_t subtype, uint8_t res __unused, uint32_t size) +{ + /* My drive doesn't export this -- so not coding up */ + printf("XXX: Erase counts subpage: %p, %#x %d\n", buf, subtype, size); +} + +static void +print_hgst_info_temp_history(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size __unused) +{ + uint8_t *walker = buf; + uint32_t min; + + printf("Temperature History:\n"); + printf(" %-30s: %d C\n", "Current Temperature", *walker++); + printf(" %-30s: %d C\n", "Reference Temperature", *walker++); + printf(" %-30s: %d C\n", "Maximum Temperature", *walker++); + printf(" %-30s: %d C\n", "Minimum Temperature", *walker++); + min = le32dec(walker); + walker += 4; + printf(" %-30s: %d:%02d:00\n", "Max Temperture Time", min / 60, min % 60); + min = le32dec(walker); + walker += 4; + printf(" %-30s: %d:%02d:00\n", "Over Temperture Duration", min / 60, min % 60); + min = le32dec(walker); + walker += 4; + printf(" %-30s: %d:%02d:00\n", "Min Temperture Time", min / 60, min % 60); +} + +static void +print_hgst_info_ssd_perf(void *buf, uint16_t subtype __unused, uint8_t res, uint32_t size __unused) +{ + uint8_t *walker = buf; + uint64_t val; + + printf("SSD Performance Subpage Type %d:\n", res); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Read Commands", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Read Blocks", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Cache Read Hits Commands", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Cache Read Hits Blocks", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Read Commands Stalled", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Write Commands", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Write Blocks", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Write Odd Start Commands", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Write Odd End Commands", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "Host Write Commands Stalled", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "NAND Read Commands", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "NAND Read Blocks", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "NAND Write Commands", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "NAND Write Blocks", val); + val = le64dec(walker); + walker += 8; + printf(" %-30s: %ju\n", "NAND Read Before Writes", val); +} + +static void +print_hgst_info_firmware_load(void *buf, uint16_t subtype __unused, uint8_t res __unused, uint32_t size __unused) +{ + uint8_t *walker = buf; + + printf("Firmware Load Subpage:\n"); + printf(" %-30s: %d\n", "Firmware Downloads", le32dec(walker)); +} + +static void +kv_indirect(void *buf, uint32_t subtype, uint8_t res, uint32_t size, struct subpage_print *sp, size_t nsp) +{ + size_t i; + + for (i = 0; i < nsp; i++, sp++) { + if (sp->key == subtype) { + sp->fn(buf, subtype, res, size); + return; + } + } + printf("No handler for page type %x\n", subtype); +} + +static void +print_hgst_info_log(void *buf, uint32_t size __unused) +{ + uint8_t *walker, *end, *subpage; + int pages; + uint16_t len; + uint8_t subtype, res; + + printf("HGST Extra Info Log\n"); + printf("===================\n"); + + walker = buf; + pages = *walker++; + walker++; + len = le16dec(walker); + walker += 2; + end = walker + len; /* Length is exclusive of this header */ + + while (walker < end) { + subpage = walker + 4; + subtype = *walker++ & 0x3f; /* subtype */ + res = *walker++; /* Reserved */ + len = le16dec(walker); + walker += len + 2; /* Length, not incl header */ + if (walker > end) { + printf("Ooops! Off the end of the list\n"); + break; + } + kv_indirect(subpage, subtype, res, len, hgst_subpage, nitems(hgst_subpage)); + } +} + +/* + * Table of log page printer / sizing. + * + * This includes Intel specific pages that are widely implemented. Not + * sure how best to switch between different vendors. + */ static struct logpage_function { uint8_t log_page; - print_fn_t fn; + print_fn_t print_fn; + size_t size; } logfuncs[] = { - {NVME_LOG_ERROR, print_log_error }, - {NVME_LOG_HEALTH_INFORMATION, print_log_health }, - {NVME_LOG_FIRMWARE_SLOT, print_log_firmware }, - {0, NULL }, + {NVME_LOG_ERROR, print_log_error, + 0}, + {NVME_LOG_HEALTH_INFORMATION, print_log_health, + sizeof(struct nvme_health_information_page)}, + {NVME_LOG_FIRMWARE_SLOT, print_log_firmware, + sizeof(struct nvme_firmware_page)}, + {INTEL_LOG_TEMP_STATS, print_intel_temp_stats, + sizeof(struct intel_log_temp_stats)}, + {INTEL_LOG_ADD_SMART, print_intel_add_smart, + DEFAULT_SIZE}, + {HGST_INFO_LOG, print_hgst_info_log, + DEFAULT_SIZE}, + {0, NULL, + 0}, }; static void logpage_usage(void) { fprintf(stderr, "usage:\n"); fprintf(stderr, LOGPAGE_USAGE); exit(1); } void logpage(int argc, char *argv[]) { int fd, nsid; int log_page = 0, pageflag = false; int hexflag = false, ns_specified; char ch, *p; char cname[64]; uint32_t size; void *buf; struct logpage_function *f; struct nvme_controller_data cdata; print_fn_t print_fn; while ((ch = getopt(argc, argv, "p:x")) != -1) { switch (ch) { case 'p': /* TODO: Add human-readable ASCII page IDs */ log_page = strtol(optarg, &p, 0); if (p != NULL && *p != '\0') { fprintf(stderr, "\"%s\" not valid log page id.\n", optarg); logpage_usage(); - /* TODO: Define valid log page id ranges in nvme.h? */ - } else if (log_page == 0 || - (log_page >= 0x04 && log_page <= 0x7F) || - (log_page >= 0x80 && log_page <= 0xBF)) { - fprintf(stderr, - "\"%s\" not valid log page id.\n", - optarg); - logpage_usage(); } pageflag = true; break; case 'x': hexflag = true; break; } } if (!pageflag) { printf("Missing page_id (-p).\n"); logpage_usage(); } /* Check that a controller and/or namespace was specified. */ if (optind >= argc) logpage_usage(); if (strstr(argv[optind], NVME_NS_PREFIX) != NULL) { ns_specified = true; parse_ns_str(argv[optind], cname, &nsid); open_dev(cname, &fd, 1, 1); } else { ns_specified = false; nsid = NVME_GLOBAL_NAMESPACE_TAG; open_dev(argv[optind], &fd, 1, 1); } read_controller_data(fd, &cdata); /* * The log page attribtues indicate whether or not the controller * supports the SMART/Health information log page on a per * namespace basis. */ if (ns_specified) { if (log_page != NVME_LOG_HEALTH_INFORMATION) errx(1, "log page %d valid only at controller level", log_page); if (cdata.lpa.ns_smart == 0) errx(1, "controller does not support per namespace " "smart/health information"); } print_fn = print_hex; + size = DEFAULT_SIZE; if (!hexflag) { /* * See if there is a pretty print function for the * specified log page. If one isn't found, we * just revert to the default (print_hex). */ f = logfuncs; while (f->log_page > 0) { if (log_page == f->log_page) { - print_fn = f->fn; + print_fn = f->print_fn; + size = f->size; break; } f++; } } - /* Read the log page */ - switch (log_page) { - case NVME_LOG_ERROR: + if (log_page == NVME_LOG_ERROR) { size = sizeof(struct nvme_error_information_entry); size *= (cdata.elpe + 1); - break; - case NVME_LOG_HEALTH_INFORMATION: - size = sizeof(struct nvme_health_information_page); - break; - case NVME_LOG_FIRMWARE_SLOT: - size = sizeof(struct nvme_firmware_page); - break; - default: - size = DEFAULT_SIZE; - break; } + /* Read the log page */ buf = get_log_buffer(size); read_logpage(fd, log_page, nsid, buf, size); print_fn(buf, size); close(fd); exit(0); } Index: projects/clang390-import/sys/boot/i386/libi386/smbios.c =================================================================== --- projects/clang390-import/sys/boot/i386/libi386/smbios.c (revision 308867) +++ projects/clang390-import/sys/boot/i386/libi386/smbios.c (revision 308868) @@ -1,453 +1,454 @@ /*- * Copyright (c) 2005-2009 Jung-uk Kim * 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 __FBSDID("$FreeBSD$"); #include #include #include #ifdef EFI /* In EFI, we don't need PTOV(). */ #define PTOV(x) (caddr_t)(x) #else #include "btxv86.h" #endif #include "smbios.h" /* * Detect SMBIOS and export information about the SMBIOS into the * environment. * * System Management BIOS Reference Specification, v2.6 Final * http://www.dmtf.org/standards/published_documents/DSP0134_2.6.0.pdf */ /* * 2.1.1 SMBIOS Structure Table Entry Point * * "On non-EFI systems, the SMBIOS Entry Point structure, described below, can * be located by application software by searching for the anchor-string on * paragraph (16-byte) boundaries within the physical memory address range * 000F0000h to 000FFFFFh. This entry point encapsulates an intermediate anchor * string that is used by some existing DMI browsers." */ #define SMBIOS_START 0xf0000 #define SMBIOS_LENGTH 0x10000 #define SMBIOS_STEP 0x10 #define SMBIOS_SIG "_SM_" #define SMBIOS_DMI_SIG "_DMI_" #define SMBIOS_GET8(base, off) (*(uint8_t *)((base) + (off))) #define SMBIOS_GET16(base, off) (*(uint16_t *)((base) + (off))) #define SMBIOS_GET32(base, off) (*(uint32_t *)((base) + (off))) #define SMBIOS_GETLEN(base) SMBIOS_GET8(base, 0x01) #define SMBIOS_GETSTR(base) ((base) + SMBIOS_GETLEN(base)) struct smbios_attr { int probed; caddr_t addr; size_t length; size_t count; int major; int minor; int ver; const char* bios_vendor; const char* maker; const char* product; uint32_t enabled_memory; uint32_t old_enabled_memory; uint8_t enabled_sockets; uint8_t populated_sockets; }; static struct smbios_attr smbios; static uint8_t smbios_checksum(const caddr_t addr, const uint8_t len) { uint8_t sum; int i; for (sum = 0, i = 0; i < len; i++) sum += SMBIOS_GET8(addr, i); return (sum); } static caddr_t smbios_sigsearch(const caddr_t addr, const uint32_t len) { caddr_t cp; /* Search on 16-byte boundaries. */ for (cp = addr; cp < addr + len; cp += SMBIOS_STEP) if (strncmp(cp, SMBIOS_SIG, 4) == 0 && smbios_checksum(cp, SMBIOS_GET8(cp, 0x05)) == 0 && strncmp(cp + 0x10, SMBIOS_DMI_SIG, 5) == 0 && smbios_checksum(cp + 0x10, 0x0f) == 0) return (cp); return (NULL); } static const char* smbios_getstring(caddr_t addr, const int offset) { caddr_t cp; int i, idx; idx = SMBIOS_GET8(addr, offset); if (idx != 0) { cp = SMBIOS_GETSTR(addr); for (i = 1; i < idx; i++) cp += strlen(cp) + 1; return cp; } return (NULL); } static void smbios_setenv(const char *name, caddr_t addr, const int offset) { const char* val; val = smbios_getstring(addr, offset); if (val != NULL) setenv(name, val, 1); } #ifdef SMBIOS_SERIAL_NUMBERS #define UUID_SIZE 16 #define UUID_TYPE uint32_t #define UUID_STEP sizeof(UUID_TYPE) #define UUID_ALL_BITS (UUID_SIZE / UUID_STEP) #define UUID_GET(base, off) (*(UUID_TYPE *)((base) + (off))) static void smbios_setuuid(const char *name, const caddr_t addr, const int ver) { char uuid[37]; int byteorder, i, ones, zeros; UUID_TYPE n; uint32_t f1; uint16_t f2, f3; for (i = 0, ones = 0, zeros = 0; i < UUID_SIZE; i += UUID_STEP) { n = UUID_GET(addr, i) + 1; if (zeros == 0 && n == 0) ones++; else if (ones == 0 && n == 1) zeros++; else break; } if (ones != UUID_ALL_BITS && zeros != UUID_ALL_BITS) { /* * 3.3.2.1 System UUID * * "Although RFC 4122 recommends network byte order for all * fields, the PC industry (including the ACPI, UEFI, and * Microsoft specifications) has consistently used * little-endian byte encoding for the first three fields: * time_low, time_mid, time_hi_and_version. The same encoding, * also known as wire format, should also be used for the * SMBIOS representation of the UUID." * * Note: We use network byte order for backward compatibility * unless SMBIOS version is 2.6+ or little-endian is forced. */ #if defined(SMBIOS_LITTLE_ENDIAN_UUID) byteorder = LITTLE_ENDIAN; #elif defined(SMBIOS_NETWORK_ENDIAN_UUID) byteorder = BIG_ENDIAN; #else byteorder = ver < 0x0206 ? BIG_ENDIAN : LITTLE_ENDIAN; #endif if (byteorder != LITTLE_ENDIAN) { f1 = ntohl(SMBIOS_GET32(addr, 0)); f2 = ntohs(SMBIOS_GET16(addr, 4)); f3 = ntohs(SMBIOS_GET16(addr, 6)); } else { f1 = le32toh(SMBIOS_GET32(addr, 0)); f2 = le16toh(SMBIOS_GET16(addr, 4)); f3 = le16toh(SMBIOS_GET16(addr, 6)); } sprintf(uuid, "%08x-%04x-%04x-%02x%02x-%02x%02x%02x%02x%02x%02x", f1, f2, f3, SMBIOS_GET8(addr, 8), SMBIOS_GET8(addr, 9), SMBIOS_GET8(addr, 10), SMBIOS_GET8(addr, 11), SMBIOS_GET8(addr, 12), SMBIOS_GET8(addr, 13), SMBIOS_GET8(addr, 14), SMBIOS_GET8(addr, 15)); setenv(name, uuid, 1); } } #undef UUID_SIZE #undef UUID_TYPE #undef UUID_STEP #undef UUID_ALL_BITS #undef UUID_GET #endif static caddr_t smbios_parse_table(const caddr_t addr) { caddr_t cp; int proc, size, osize, type; type = SMBIOS_GET8(addr, 0); /* 3.1.2 Structure Header Format */ switch(type) { case 0: /* 3.3.1 BIOS Information (Type 0) */ smbios_setenv("smbios.bios.vendor", addr, 0x04); smbios_setenv("smbios.bios.version", addr, 0x05); smbios_setenv("smbios.bios.reldate", addr, 0x08); break; case 1: /* 3.3.2 System Information (Type 1) */ smbios_setenv("smbios.system.maker", addr, 0x04); smbios_setenv("smbios.system.product", addr, 0x05); smbios_setenv("smbios.system.version", addr, 0x06); #ifdef SMBIOS_SERIAL_NUMBERS smbios_setenv("smbios.system.serial", addr, 0x07); smbios_setuuid("smbios.system.uuid", addr + 0x08, smbios.ver); #endif - if (smbios.major >= 2 && smbios.minor >= 4) { + if (smbios.major > 2 || + (smbios.major == 2 && smbios.minor >= 4)) { smbios_setenv("smbios.system.sku", addr, 0x19); smbios_setenv("smbios.system.family", addr, 0x1a); } break; case 2: /* 3.3.3 Base Board (or Module) Information (Type 2) */ smbios_setenv("smbios.planar.maker", addr, 0x04); smbios_setenv("smbios.planar.product", addr, 0x05); smbios_setenv("smbios.planar.version", addr, 0x06); #ifdef SMBIOS_SERIAL_NUMBERS smbios_setenv("smbios.planar.serial", addr, 0x07); smbios_setenv("smbios.planar.tag", addr, 0x08); #endif smbios_setenv("smbios.planar.location", addr, 0x0a); break; case 3: /* 3.3.4 System Enclosure or Chassis (Type 3) */ smbios_setenv("smbios.chassis.maker", addr, 0x04); smbios_setenv("smbios.chassis.version", addr, 0x06); #ifdef SMBIOS_SERIAL_NUMBERS smbios_setenv("smbios.chassis.serial", addr, 0x07); smbios_setenv("smbios.chassis.tag", addr, 0x08); #endif break; case 4: /* 3.3.5 Processor Information (Type 4) */ /* * Offset 18h: Processor Status * * Bit 7 Reserved, must be 0 * Bit 6 CPU Socket Populated * 1 - CPU Socket Populated * 0 - CPU Socket Unpopulated * Bit 5:3 Reserved, must be zero * Bit 2:0 CPU Status * 0h - Unknown * 1h - CPU Enabled * 2h - CPU Disabled by User via BIOS Setup * 3h - CPU Disabled by BIOS (POST Error) * 4h - CPU is Idle, waiting to be enabled * 5-6h - Reserved * 7h - Other */ proc = SMBIOS_GET8(addr, 0x18); if ((proc & 0x07) == 1) smbios.enabled_sockets++; if ((proc & 0x40) != 0) smbios.populated_sockets++; break; case 6: /* 3.3.7 Memory Module Information (Type 6, Obsolete) */ /* * Offset 0Ah: Enabled Size * * Bit 7 Bank connection * 1 - Double-bank connection * 0 - Single-bank connection * Bit 6:0 Size (n), where 2**n is the size in MB * 7Dh - Not determinable (Installed Size only) * 7Eh - Module is installed, but no memory * has been enabled * 7Fh - Not installed */ osize = SMBIOS_GET8(addr, 0x0a) & 0x7f; if (osize > 0 && osize < 22) smbios.old_enabled_memory += 1 << (osize + 10); break; case 17: /* 3.3.18 Memory Device (Type 17) */ /* * Offset 0Ch: Size * * Bit 15 Granularity * 1 - Value is in kilobytes units * 0 - Value is in megabytes units * Bit 14:0 Size */ size = SMBIOS_GET16(addr, 0x0c); if (size != 0 && size != 0xffff) smbios.enabled_memory += (size & 0x8000) != 0 ? (size & 0x7fff) : (size << 10); break; default: /* skip other types */ break; } /* Find structure terminator. */ cp = SMBIOS_GETSTR(addr); while (SMBIOS_GET16(cp, 0) != 0) cp++; return (cp + 2); } static caddr_t smbios_find_struct(int type) { caddr_t dmi; size_t i; if (smbios.addr == NULL) return (NULL); for (dmi = smbios.addr, i = 0; dmi < smbios.addr + smbios.length && i < smbios.count; i++) { if (SMBIOS_GET8(dmi, 0) == type) return dmi; /* Find structure terminator. */ dmi = SMBIOS_GETSTR(dmi); while (SMBIOS_GET16(dmi, 0) != 0) dmi++; dmi += 2; } return (NULL); } static void smbios_probe(const caddr_t addr) { caddr_t saddr, info; uintptr_t paddr; if (smbios.probed) return; smbios.probed = 1; /* Search signatures and validate checksums. */ saddr = smbios_sigsearch(addr ? addr : PTOV(SMBIOS_START), SMBIOS_LENGTH); if (saddr == NULL) return; smbios.length = SMBIOS_GET16(saddr, 0x16); /* Structure Table Length */ paddr = SMBIOS_GET32(saddr, 0x18); /* Structure Table Address */ smbios.count = SMBIOS_GET16(saddr, 0x1c); /* No of SMBIOS Structures */ smbios.ver = SMBIOS_GET8(saddr, 0x1e); /* SMBIOS BCD Revision */ if (smbios.ver != 0) { smbios.major = smbios.ver >> 4; smbios.minor = smbios.ver & 0x0f; if (smbios.major > 9 || smbios.minor > 9) smbios.ver = 0; } if (smbios.ver == 0) { smbios.major = SMBIOS_GET8(saddr, 0x06);/* SMBIOS Major Version */ smbios.minor = SMBIOS_GET8(saddr, 0x07);/* SMBIOS Minor Version */ } smbios.ver = (smbios.major << 8) | smbios.minor; smbios.addr = PTOV(paddr); /* Get system information from SMBIOS */ info = smbios_find_struct(0x00); if (info != NULL) { smbios.bios_vendor = smbios_getstring(info, 0x04); } info = smbios_find_struct(0x01); if (info != NULL) { smbios.maker = smbios_getstring(info, 0x04); smbios.product = smbios_getstring(info, 0x05); } } void smbios_detect(const caddr_t addr) { char buf[16]; caddr_t dmi; size_t i; smbios_probe(addr); if (smbios.addr == NULL) return; for (dmi = smbios.addr, i = 0; dmi < smbios.addr + smbios.length && i < smbios.count; i++) dmi = smbios_parse_table(dmi); sprintf(buf, "%d.%d", smbios.major, smbios.minor); setenv("smbios.version", buf, 1); if (smbios.enabled_memory > 0 || smbios.old_enabled_memory > 0) { sprintf(buf, "%u", smbios.enabled_memory > 0 ? smbios.enabled_memory : smbios.old_enabled_memory); setenv("smbios.memory.enabled", buf, 1); } if (smbios.enabled_sockets > 0) { sprintf(buf, "%u", smbios.enabled_sockets); setenv("smbios.socket.enabled", buf, 1); } if (smbios.populated_sockets > 0) { sprintf(buf, "%u", smbios.populated_sockets); setenv("smbios.socket.populated", buf, 1); } } static int smbios_match_str(const char* s1, const char* s2) { return (s1 == NULL || (s2 != NULL && !strcmp(s1, s2))); } int smbios_match(const char* bios_vendor, const char* maker, const char* product) { /* XXXRP currently, only called from non-EFI. */ smbios_probe(NULL); return (smbios_match_str(bios_vendor, smbios.bios_vendor) && smbios_match_str(maker, smbios.maker) && smbios_match_str(product, smbios.product)); } Index: projects/clang390-import/sys/conf/files.mips =================================================================== --- projects/clang390-import/sys/conf/files.mips (revision 308867) +++ projects/clang390-import/sys/conf/files.mips (revision 308868) @@ -1,104 +1,111 @@ # This file tells config what files go into building a kernel, # files marked standard are always included. # # $FreeBSD$ # # Arch dependent files mips/mips/autoconf.c standard mips/mips/bus_space_generic.c standard mips/mips/busdma_machdep.c standard mips/mips/cache.c standard mips/mips/cache_mipsNN.c standard mips/mips/cpu.c standard mips/mips/db_disasm.c optional ddb mips/mips/db_interface.c optional ddb mips/mips/db_trace.c optional ddb mips/mips/dump_machdep.c standard mips/mips/elf_machdep.c standard mips/mips/exception.S standard mips/mips/fp.S standard mips/mips/freebsd32_machdep.c optional compat_freebsd32 mips/mips/gdb_machdep.c standard mips/mips/in_cksum.c optional inet mips/mips/libkern_machdep.c standard mips/mips/locore.S standard no-obj mips/mips/machdep.c standard mips/mips/mem.c optional mem mips/mips/minidump_machdep.c standard mips/mips/mp_machdep.c optional smp mips/mips/mpboot.S optional smp mips/mips/nexus.c standard mips/mips/ofw_machdep.c optional fdt mips/mips/pm_machdep.c standard mips/mips/pmap.c standard mips/mips/ptrace_machdep.c standard mips/mips/sc_machdep.c standard mips/mips/stack_machdep.c optional ddb | stack mips/mips/stdatomic.c standard \ compile-with "${NORMAL_C:N-Wmissing-prototypes}" mips/mips/support.S standard mips/mips/bcopy.S standard mips/mips/swtch.S standard mips/mips/sys_machdep.c standard mips/mips/tlb.c standard mips/mips/trap.c standard mips/mips/uio_machdep.c standard mips/mips/uma_machdep.c standard mips/mips/vm_machdep.c standard # misc opt-in bits kern/kern_clocksource.c standard kern/link_elf_obj.c standard kern/subr_busdma_bufalloc.c standard kern/subr_dummy_vdso_tc.c standard kern/subr_sfbuf.c optional mips | mipsel | mipsn32 # gcc/clang runtime libkern/ffsl.c standard libkern/ffsll.c standard libkern/fls.c standard libkern/flsl.c standard libkern/flsll.c standard libkern/memmove.c standard libkern/cmpdi2.c optional mips | mipsel libkern/ucmpdi2.c optional mips | mipsel libkern/ashldi3.c standard libkern/ashrdi3.c standard # cfe support dev/cfe/cfe_api.c optional cfe dev/cfe/cfe_console.c optional cfe_console dev/cfe/cfe_env.c optional cfe_env # syscons support dev/fb/fb.c optional sc dev/syscons/scgfbrndr.c optional sc dev/syscons/scterm-teken.c optional sc dev/syscons/scvtb.c optional sc mips/mips/sc_machdep.c optional sc # FDT support dev/uart/uart_cpu_fdt.c optional uart fdt # crypto support -- use generic crypto/blowfish/bf_enc.c optional crypto | ipsec crypto/des/des_enc.c optional crypto | ipsec | netsmb # AP common nvram interface MIPS specific, but maybe should be more generic dev/nvram2env/nvram2env_mips.c optional nvram2env dev/nvram2env/nvram2env.c optional nvram2env # hwpmc support dev/hwpmc/hwpmc_mips.c optional hwpmc dev/hwpmc/hwpmc_mips24k.c optional hwpmc_mips24k dev/hwpmc/hwpmc_mips74k.c optional hwpmc_mips74k # ofw support dev/ofw/ofwpci.c optional fdt pci +# INTRNG support code +kern/msi_if.m optional intrng +kern/pic_if.m optional intrng +kern/subr_intr.c optional intrng +# INTRNG compatible MIPS32 interrupt controller +mips/mips/mips_pic.c optional intrng + # DTrace cddl/compat/opensolaris/kern/opensolaris_atomic.c optional zfs | dtrace compile-with "${CDDL_C}" cddl/dev/dtrace/mips/dtrace_asm.S optional dtrace compile-with "${DTRACE_S}" cddl/dev/dtrace/mips/dtrace_subr.c optional dtrace compile-with "${DTRACE_C}" cddl/dev/fbt/mips/fbt_isa.c optional dtrace_fbt | dtraceall compile-with "${FBT_C}" Index: projects/clang390-import/sys/conf/options.mips =================================================================== --- projects/clang390-import/sys/conf/options.mips (revision 308867) +++ projects/clang390-import/sys/conf/options.mips (revision 308868) @@ -1,160 +1,161 @@ # Copyright (c) 2001, 2008, Juniper Networks, Inc. # 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. # 3. Neither the name of the Juniper Networks, Inc. nor the names of its # contributors may be used to endorse or promote products derived from # this software without specific prior written permission. # # THIS SOFTWARE IS PROVIDED BY JUNIPER NETWORKS 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 JUNIPER NETWORKS 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. # # JNPR: options.mips,v 1.2 2006/09/15 12:52:34 # $FreeBSD$ CPU_MIPS4KC opt_global.h CPU_MIPS24K opt_global.h CPU_MIPS34K opt_global.h CPU_MIPS74K opt_global.h CPU_MIPS1004K opt_global.h CPU_MIPS1074K opt_global.h CPU_INTERAPTIV opt_global.h CPU_PROAPTIV opt_global.h CPU_MIPS32 opt_global.h CPU_MIPS64 opt_global.h CPU_SENTRY5 opt_global.h CPU_HAVEFPU opt_global.h CPU_SB1 opt_global.h CPU_CNMIPS opt_global.h CPU_RMI opt_global.h CPU_NLM opt_global.h CPU_BERI opt_global.h +CPU_XBURST opt_global.h CPU_MALTA opt_global.h # which MACHINE_ARCH architecture MIPS MIPSEL MIPS64 MIPS64EL MIPSN32 COMPAT_FREEBSD32 opt_compat.h YAMON opt_global.h CFE opt_global.h CFE_CONSOLE opt_global.h CFE_ENV opt_global.h CFE_ENV_SIZE opt_global.h GFB_DEBUG opt_gfb.h GFB_NO_FONT_LOADING opt_gfb.h GFB_NO_MODE_CHANGE opt_gfb.h NOFPU opt_global.h TICK_USE_YAMON_FREQ opt_global.h TICK_USE_MALTA_RTC opt_global.h # # The highest memory address that can be used by the kernel in units of KB. # MAXMEM opt_global.h # # Manual override of cache config # MIPS_DISABLE_L1_CACHE opt_global.h # # Options that control the Cavium Simple Executive. # OCTEON_MODEL opt_cvmx.h OCTEON_VENDOR_LANNER opt_cvmx.h OCTEON_VENDOR_UBIQUITI opt_cvmx.h OCTEON_VENDOR_RADISYS opt_cvmx.h OCTEON_VENDOR_GEFES opt_cvmx.h OCTEON_BOARD_CAPK_0100ND opt_cvmx.h # # Options specific to the BERI platform. # BERI_LARGE_TLB opt_global.h # # Options that control the NetFPGA-10G Embedded CPU Ethernet Core. # NF10BMAC_64BIT opt_netfpga.h # # Options that control the Atheros SoC peripherals # ARGE_DEBUG opt_arge.h ARGE_MDIO opt_arge.h # # At least one of the AR71XX ubiquiti boards has a Redboot configuration # that "lies" about the amount of RAM it has. Until a cleaner method is # defined, this option will suffice in overriding what Redboot says. # AR71XX_REALMEM opt_ar71xx.h AR71XX_ENV_UBOOT opt_ar71xx.h AR71XX_ENV_REDBOOT opt_ar71xx.h AR71XX_ENV_ROUTERBOOT opt_ar71xx.h AR71XX_ATH_EEPROM opt_ar71xx.h # # Options for AR531X SOC. AR531X_1ST_GENERATION is AR5311 to AR5314. # AR531X_1ST_GENERATION opt_ar531x.h AR531X_REALMEM opt_ar531x.h AR531X_ENV_UBOOT opt_ar531x.h AR531X_APB_DEBUG opt_ar531x.h ARE_MDIO opt_ar531x.h ARE_MII opt_ar531x.h # # Options that control the Ralink RT305xF Etherenet MAC. # IF_RT_DEBUG opt_if_rt.h IF_RT_PHY_SUPPORT opt_if_rt.h IF_RT_RING_DATA_COUNT opt_if_rt.h # # Options that control the Ralink/Mediatek SoC type. # MT7620 opt_rt305x.h RT5350 opt_rt305x.h RT305XF opt_rt305x.h RT3052F opt_rt305x.h RT3050F opt_rt305x.h RT305X opt_rt305x.h RT305X_UBOOT opt_rt305x.h RT305X_USE_UART opt_rt305x.h # # Options that affect the pmap. # PV_STATS opt_pmap.h # # Options to use INTRNG code # INTRNG opt_global.h MIPS_NIRQ opt_global.h Index: projects/clang390-import/sys/dev/nvme/nvme.h =================================================================== --- projects/clang390-import/sys/dev/nvme/nvme.h (revision 308867) +++ projects/clang390-import/sys/dev/nvme/nvme.h (revision 308868) @@ -1,957 +1,991 @@ /*- * Copyright (C) 2012-2013 Intel Corporation * 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. * * $FreeBSD$ */ #ifndef __NVME_H__ #define __NVME_H__ #ifdef _KERNEL #include #endif #include #define NVME_PASSTHROUGH_CMD _IOWR('n', 0, struct nvme_pt_command) #define NVME_RESET_CONTROLLER _IO('n', 1) #define NVME_IO_TEST _IOWR('n', 100, struct nvme_io_test) #define NVME_BIO_TEST _IOWR('n', 101, struct nvme_io_test) /* * Use to mark a command to apply to all namespaces, or to retrieve global * log pages. */ #define NVME_GLOBAL_NAMESPACE_TAG ((uint32_t)0xFFFFFFFF) /* Cap nvme to 1MB transfers driver explodes with larger sizes */ #define NVME_MAX_XFER_SIZE (MAXPHYS < (1<<20) ? MAXPHYS : (1<<20)) union cap_lo_register { uint32_t raw; struct { /** maximum queue entries supported */ uint32_t mqes : 16; /** contiguous queues required */ uint32_t cqr : 1; /** arbitration mechanism supported */ uint32_t ams : 2; uint32_t reserved1 : 5; /** timeout */ uint32_t to : 8; } bits __packed; } __packed; union cap_hi_register { uint32_t raw; struct { /** doorbell stride */ uint32_t dstrd : 4; uint32_t reserved3 : 1; /** command sets supported */ uint32_t css_nvm : 1; uint32_t css_reserved : 3; uint32_t reserved2 : 7; /** memory page size minimum */ uint32_t mpsmin : 4; /** memory page size maximum */ uint32_t mpsmax : 4; uint32_t reserved1 : 8; } bits __packed; } __packed; union cc_register { uint32_t raw; struct { /** enable */ uint32_t en : 1; uint32_t reserved1 : 3; /** i/o command set selected */ uint32_t css : 3; /** memory page size */ uint32_t mps : 4; /** arbitration mechanism selected */ uint32_t ams : 3; /** shutdown notification */ uint32_t shn : 2; /** i/o submission queue entry size */ uint32_t iosqes : 4; /** i/o completion queue entry size */ uint32_t iocqes : 4; uint32_t reserved2 : 8; } bits __packed; } __packed; enum shn_value { NVME_SHN_NORMAL = 0x1, NVME_SHN_ABRUPT = 0x2, }; union csts_register { uint32_t raw; struct { /** ready */ uint32_t rdy : 1; /** controller fatal status */ uint32_t cfs : 1; /** shutdown status */ uint32_t shst : 2; uint32_t reserved1 : 28; } bits __packed; } __packed; enum shst_value { NVME_SHST_NORMAL = 0x0, NVME_SHST_OCCURRING = 0x1, NVME_SHST_COMPLETE = 0x2, }; union aqa_register { uint32_t raw; struct { /** admin submission queue size */ uint32_t asqs : 12; uint32_t reserved1 : 4; /** admin completion queue size */ uint32_t acqs : 12; uint32_t reserved2 : 4; } bits __packed; } __packed; struct nvme_registers { /** controller capabilities */ union cap_lo_register cap_lo; union cap_hi_register cap_hi; uint32_t vs; /* version */ uint32_t intms; /* interrupt mask set */ uint32_t intmc; /* interrupt mask clear */ /** controller configuration */ union cc_register cc; uint32_t reserved1; /** controller status */ union csts_register csts; uint32_t reserved2; /** admin queue attributes */ union aqa_register aqa; uint64_t asq; /* admin submission queue base addr */ uint64_t acq; /* admin completion queue base addr */ uint32_t reserved3[0x3f2]; struct { uint32_t sq_tdbl; /* submission queue tail doorbell */ uint32_t cq_hdbl; /* completion queue head doorbell */ } doorbell[1] __packed; } __packed; struct nvme_command { /* dword 0 */ uint16_t opc : 8; /* opcode */ uint16_t fuse : 2; /* fused operation */ uint16_t rsvd1 : 6; uint16_t cid; /* command identifier */ /* dword 1 */ uint32_t nsid; /* namespace identifier */ /* dword 2-3 */ uint32_t rsvd2; uint32_t rsvd3; /* dword 4-5 */ uint64_t mptr; /* metadata pointer */ /* dword 6-7 */ uint64_t prp1; /* prp entry 1 */ /* dword 8-9 */ uint64_t prp2; /* prp entry 2 */ /* dword 10-15 */ uint32_t cdw10; /* command-specific */ uint32_t cdw11; /* command-specific */ uint32_t cdw12; /* command-specific */ uint32_t cdw13; /* command-specific */ uint32_t cdw14; /* command-specific */ uint32_t cdw15; /* command-specific */ } __packed; struct nvme_status { uint16_t p : 1; /* phase tag */ uint16_t sc : 8; /* status code */ uint16_t sct : 3; /* status code type */ uint16_t rsvd2 : 2; uint16_t m : 1; /* more */ uint16_t dnr : 1; /* do not retry */ } __packed; struct nvme_completion { /* dword 0 */ uint32_t cdw0; /* command-specific */ /* dword 1 */ uint32_t rsvd1; /* dword 2 */ uint16_t sqhd; /* submission queue head pointer */ uint16_t sqid; /* submission queue identifier */ /* dword 3 */ uint16_t cid; /* command identifier */ struct nvme_status status; } __packed; struct nvme_dsm_range { uint32_t attributes; uint32_t length; uint64_t starting_lba; } __packed; /* status code types */ enum nvme_status_code_type { NVME_SCT_GENERIC = 0x0, NVME_SCT_COMMAND_SPECIFIC = 0x1, NVME_SCT_MEDIA_ERROR = 0x2, /* 0x3-0x6 - reserved */ NVME_SCT_VENDOR_SPECIFIC = 0x7, }; /* generic command status codes */ enum nvme_generic_command_status_code { NVME_SC_SUCCESS = 0x00, NVME_SC_INVALID_OPCODE = 0x01, NVME_SC_INVALID_FIELD = 0x02, NVME_SC_COMMAND_ID_CONFLICT = 0x03, NVME_SC_DATA_TRANSFER_ERROR = 0x04, NVME_SC_ABORTED_POWER_LOSS = 0x05, NVME_SC_INTERNAL_DEVICE_ERROR = 0x06, NVME_SC_ABORTED_BY_REQUEST = 0x07, NVME_SC_ABORTED_SQ_DELETION = 0x08, NVME_SC_ABORTED_FAILED_FUSED = 0x09, NVME_SC_ABORTED_MISSING_FUSED = 0x0a, NVME_SC_INVALID_NAMESPACE_OR_FORMAT = 0x0b, NVME_SC_COMMAND_SEQUENCE_ERROR = 0x0c, NVME_SC_LBA_OUT_OF_RANGE = 0x80, NVME_SC_CAPACITY_EXCEEDED = 0x81, NVME_SC_NAMESPACE_NOT_READY = 0x82, }; /* command specific status codes */ enum nvme_command_specific_status_code { NVME_SC_COMPLETION_QUEUE_INVALID = 0x00, NVME_SC_INVALID_QUEUE_IDENTIFIER = 0x01, NVME_SC_MAXIMUM_QUEUE_SIZE_EXCEEDED = 0x02, NVME_SC_ABORT_COMMAND_LIMIT_EXCEEDED = 0x03, /* 0x04 - reserved */ NVME_SC_ASYNC_EVENT_REQUEST_LIMIT_EXCEEDED = 0x05, NVME_SC_INVALID_FIRMWARE_SLOT = 0x06, NVME_SC_INVALID_FIRMWARE_IMAGE = 0x07, NVME_SC_INVALID_INTERRUPT_VECTOR = 0x08, NVME_SC_INVALID_LOG_PAGE = 0x09, NVME_SC_INVALID_FORMAT = 0x0a, NVME_SC_FIRMWARE_REQUIRES_RESET = 0x0b, NVME_SC_CONFLICTING_ATTRIBUTES = 0x80, NVME_SC_INVALID_PROTECTION_INFO = 0x81, NVME_SC_ATTEMPTED_WRITE_TO_RO_PAGE = 0x82, }; /* media error status codes */ enum nvme_media_error_status_code { NVME_SC_WRITE_FAULTS = 0x80, NVME_SC_UNRECOVERED_READ_ERROR = 0x81, NVME_SC_GUARD_CHECK_ERROR = 0x82, NVME_SC_APPLICATION_TAG_CHECK_ERROR = 0x83, NVME_SC_REFERENCE_TAG_CHECK_ERROR = 0x84, NVME_SC_COMPARE_FAILURE = 0x85, NVME_SC_ACCESS_DENIED = 0x86, }; /* admin opcodes */ enum nvme_admin_opcode { NVME_OPC_DELETE_IO_SQ = 0x00, NVME_OPC_CREATE_IO_SQ = 0x01, NVME_OPC_GET_LOG_PAGE = 0x02, /* 0x03 - reserved */ NVME_OPC_DELETE_IO_CQ = 0x04, NVME_OPC_CREATE_IO_CQ = 0x05, NVME_OPC_IDENTIFY = 0x06, /* 0x07 - reserved */ NVME_OPC_ABORT = 0x08, NVME_OPC_SET_FEATURES = 0x09, NVME_OPC_GET_FEATURES = 0x0a, /* 0x0b - reserved */ NVME_OPC_ASYNC_EVENT_REQUEST = 0x0c, /* 0x0d-0x0f - reserved */ NVME_OPC_FIRMWARE_ACTIVATE = 0x10, NVME_OPC_FIRMWARE_IMAGE_DOWNLOAD = 0x11, NVME_OPC_FORMAT_NVM = 0x80, NVME_OPC_SECURITY_SEND = 0x81, NVME_OPC_SECURITY_RECEIVE = 0x82, }; /* nvme nvm opcodes */ enum nvme_nvm_opcode { NVME_OPC_FLUSH = 0x00, NVME_OPC_WRITE = 0x01, NVME_OPC_READ = 0x02, /* 0x03 - reserved */ NVME_OPC_WRITE_UNCORRECTABLE = 0x04, NVME_OPC_COMPARE = 0x05, /* 0x06-0x07 - reserved */ NVME_OPC_DATASET_MANAGEMENT = 0x09, }; enum nvme_feature { /* 0x00 - reserved */ NVME_FEAT_ARBITRATION = 0x01, NVME_FEAT_POWER_MANAGEMENT = 0x02, NVME_FEAT_LBA_RANGE_TYPE = 0x03, NVME_FEAT_TEMPERATURE_THRESHOLD = 0x04, NVME_FEAT_ERROR_RECOVERY = 0x05, NVME_FEAT_VOLATILE_WRITE_CACHE = 0x06, NVME_FEAT_NUMBER_OF_QUEUES = 0x07, NVME_FEAT_INTERRUPT_COALESCING = 0x08, NVME_FEAT_INTERRUPT_VECTOR_CONFIGURATION = 0x09, NVME_FEAT_WRITE_ATOMICITY = 0x0A, NVME_FEAT_ASYNC_EVENT_CONFIGURATION = 0x0B, /* 0x0C-0x7F - reserved */ NVME_FEAT_SOFTWARE_PROGRESS_MARKER = 0x80, /* 0x81-0xBF - command set specific (reserved) */ /* 0xC0-0xFF - vendor specific */ }; enum nvme_dsm_attribute { NVME_DSM_ATTR_INTEGRAL_READ = 0x1, NVME_DSM_ATTR_INTEGRAL_WRITE = 0x2, NVME_DSM_ATTR_DEALLOCATE = 0x4, }; enum nvme_activate_action { NVME_AA_REPLACE_NO_ACTIVATE = 0x0, NVME_AA_REPLACE_ACTIVATE = 0x1, NVME_AA_ACTIVATE = 0x2, }; struct nvme_power_state { /** Maximum Power */ uint16_t mp; /* Maximum Power */ uint8_t ps_rsvd1; uint8_t mps : 1; /* Max Power Scale */ uint8_t nops : 1; /* Non-Operational State */ uint8_t ps_rsvd2 : 6; uint32_t enlat; /* Entry Latency */ uint32_t exlat; /* Exit Latency */ uint8_t rrt : 5; /* Relative Read Throughput */ uint8_t ps_rsvd3 : 3; uint8_t rrl : 5; /* Relative Read Latency */ uint8_t ps_rsvd4 : 3; uint8_t rwt : 5; /* Relative Write Throughput */ uint8_t ps_rsvd5 : 3; uint8_t rwl : 5; /* Relative Write Latency */ uint8_t ps_rsvd6 : 3; uint16_t idlp; /* Idle Power */ uint8_t ps_rsvd7 : 6; uint8_t ips : 2; /* Idle Power Scale */ uint8_t ps_rsvd8; uint16_t actp; /* Active Power */ uint8_t apw : 3; /* Active Power Workload */ uint8_t ps_rsvd9 : 3; uint8_t aps : 2; /* Active Power Scale */ uint8_t ps_rsvd10[9]; } __packed; #define NVME_SERIAL_NUMBER_LENGTH 20 #define NVME_MODEL_NUMBER_LENGTH 40 #define NVME_FIRMWARE_REVISION_LENGTH 8 struct nvme_controller_data { /* bytes 0-255: controller capabilities and features */ /** pci vendor id */ uint16_t vid; /** pci subsystem vendor id */ uint16_t ssvid; /** serial number */ uint8_t sn[NVME_SERIAL_NUMBER_LENGTH]; /** model number */ uint8_t mn[NVME_MODEL_NUMBER_LENGTH]; /** firmware revision */ uint8_t fr[NVME_FIRMWARE_REVISION_LENGTH]; /** recommended arbitration burst */ uint8_t rab; /** ieee oui identifier */ uint8_t ieee[3]; /** multi-interface capabilities */ uint8_t mic; /** maximum data transfer size */ uint8_t mdts; uint8_t reserved1[178]; /* bytes 256-511: admin command set attributes */ /** optional admin command support */ struct { /* supports security send/receive commands */ uint16_t security : 1; /* supports format nvm command */ uint16_t format : 1; /* supports firmware activate/download commands */ uint16_t firmware : 1; uint16_t oacs_rsvd : 13; } __packed oacs; /** abort command limit */ uint8_t acl; /** asynchronous event request limit */ uint8_t aerl; /** firmware updates */ struct { /* first slot is read-only */ uint8_t slot1_ro : 1; /* number of firmware slots */ uint8_t num_slots : 3; uint8_t frmw_rsvd : 4; } __packed frmw; /** log page attributes */ struct { /* per namespace smart/health log page */ uint8_t ns_smart : 1; uint8_t lpa_rsvd : 7; } __packed lpa; /** error log page entries */ uint8_t elpe; /** number of power states supported */ uint8_t npss; /** admin vendor specific command configuration */ struct { /* admin vendor specific commands use spec format */ uint8_t spec_format : 1; uint8_t avscc_rsvd : 7; } __packed avscc; uint8_t reserved2[247]; /* bytes 512-703: nvm command set attributes */ /** submission queue entry size */ struct { uint8_t min : 4; uint8_t max : 4; } __packed sqes; /** completion queue entry size */ struct { uint8_t min : 4; uint8_t max : 4; } __packed cqes; uint8_t reserved3[2]; /** number of namespaces */ uint32_t nn; /** optional nvm command support */ struct { uint16_t compare : 1; uint16_t write_unc : 1; uint16_t dsm: 1; uint16_t reserved: 13; } __packed oncs; /** fused operation support */ uint16_t fuses; /** format nvm attributes */ uint8_t fna; /** volatile write cache */ struct { uint8_t present : 1; uint8_t reserved : 7; } __packed vwc; /* TODO: flesh out remaining nvm command set attributes */ uint8_t reserved4[178]; /* bytes 704-2047: i/o command set attributes */ uint8_t reserved5[1344]; /* bytes 2048-3071: power state descriptors */ struct nvme_power_state power_state[32]; /* bytes 3072-4095: vendor specific */ uint8_t vs[1024]; } __packed __aligned(4); struct nvme_namespace_data { /** namespace size */ uint64_t nsze; /** namespace capacity */ uint64_t ncap; /** namespace utilization */ uint64_t nuse; /** namespace features */ struct { /** thin provisioning */ uint8_t thin_prov : 1; uint8_t reserved1 : 7; } __packed nsfeat; /** number of lba formats */ uint8_t nlbaf; /** formatted lba size */ struct { uint8_t format : 4; uint8_t extended : 1; uint8_t reserved2 : 3; } __packed flbas; /** metadata capabilities */ struct { /* metadata can be transferred as part of data prp list */ uint8_t extended : 1; /* metadata can be transferred with separate metadata pointer */ uint8_t pointer : 1; uint8_t reserved3 : 6; } __packed mc; /** end-to-end data protection capabilities */ struct { /* protection information type 1 */ uint8_t pit1 : 1; /* protection information type 2 */ uint8_t pit2 : 1; /* protection information type 3 */ uint8_t pit3 : 1; /* first eight bytes of metadata */ uint8_t md_start : 1; /* last eight bytes of metadata */ uint8_t md_end : 1; } __packed dpc; /** end-to-end data protection type settings */ struct { /* protection information type */ uint8_t pit : 3; /* 1 == protection info transferred at start of metadata */ /* 0 == protection info transferred at end of metadata */ uint8_t md_start : 1; uint8_t reserved4 : 4; } __packed dps; uint8_t reserved5[98]; /** lba format support */ struct { /** metadata size */ uint32_t ms : 16; /** lba data size */ uint32_t lbads : 8; /** relative performance */ uint32_t rp : 2; uint32_t reserved6 : 6; } __packed lbaf[16]; uint8_t reserved6[192]; uint8_t vendor_specific[3712]; } __packed __aligned(4); enum nvme_log_page { /* 0x00 - reserved */ NVME_LOG_ERROR = 0x01, NVME_LOG_HEALTH_INFORMATION = 0x02, NVME_LOG_FIRMWARE_SLOT = 0x03, - /* 0x04-0x7F - reserved */ + NVME_LOG_CHANGED_NAMESPACE = 0x04, + NVME_LOG_COMMAND_EFFECT = 0x05, + /* 0x06-0x7F - reserved */ /* 0x80-0xBF - I/O command set specific */ + NVME_LOG_RES_NOTIFICATION = 0x80, /* 0xC0-0xFF - vendor specific */ + + /* + * The following are Intel Specific log pages, but they seem + * to be widely implemented. + */ + INTEL_LOG_READ_LAT_LOG = 0xc1, + INTEL_LOG_WRITE_LAT_LOG = 0xc2, + INTEL_LOG_TEMP_STATS = 0xc5, + INTEL_LOG_ADD_SMART = 0xca, + INTEL_LOG_DRIVE_MKT_NAME = 0xdd, + + /* + * HGST log page, with lots ofs sub pages. + */ + HGST_INFO_LOG = 0xc1, }; struct nvme_error_information_entry { uint64_t error_count; uint16_t sqid; uint16_t cid; struct nvme_status status; uint16_t error_location; uint64_t lba; uint32_t nsid; uint8_t vendor_specific; uint8_t reserved[35]; } __packed __aligned(4); union nvme_critical_warning_state { uint8_t raw; struct { uint8_t available_spare : 1; uint8_t temperature : 1; uint8_t device_reliability : 1; uint8_t read_only : 1; uint8_t volatile_memory_backup : 1; uint8_t reserved : 3; } __packed bits; } __packed; struct nvme_health_information_page { union nvme_critical_warning_state critical_warning; uint16_t temperature; uint8_t available_spare; uint8_t available_spare_threshold; uint8_t percentage_used; uint8_t reserved[26]; /* * Note that the following are 128-bit values, but are * defined as an array of 2 64-bit values. */ /* Data Units Read is always in 512-byte units. */ uint64_t data_units_read[2]; /* Data Units Written is always in 512-byte units. */ uint64_t data_units_written[2]; /* For NVM command set, this includes Compare commands. */ uint64_t host_read_commands[2]; uint64_t host_write_commands[2]; /* Controller Busy Time is reported in minutes. */ uint64_t controller_busy_time[2]; uint64_t power_cycles[2]; uint64_t power_on_hours[2]; uint64_t unsafe_shutdowns[2]; uint64_t media_errors[2]; uint64_t num_error_info_log_entries[2]; + uint32_t warning_temp_time; + uint32_t error_temp_time; + uint16_t temp_sensor[8]; - uint8_t reserved2[320]; + uint8_t reserved2[296]; } __packed __aligned(4); struct nvme_firmware_page { struct { uint8_t slot : 3; /* slot for current FW */ uint8_t reserved : 5; } __packed afi; uint8_t reserved[7]; uint64_t revision[7]; /* revisions for 7 slots */ uint8_t reserved2[448]; +} __packed __aligned(4); + +struct intel_log_temp_stats +{ + uint64_t current; + uint64_t overtemp_flag_last; + uint64_t overtemp_flag_life; + uint64_t max_temp; + uint64_t min_temp; + uint64_t _rsvd[5]; + uint64_t max_oper_temp; + uint64_t min_oper_temp; + uint64_t est_offset; } __packed __aligned(4); #define NVME_TEST_MAX_THREADS 128 struct nvme_io_test { enum nvme_nvm_opcode opc; uint32_t size; uint32_t time; /* in seconds */ uint32_t num_threads; uint32_t flags; uint64_t io_completed[NVME_TEST_MAX_THREADS]; }; enum nvme_io_test_flags { /* * Specifies whether dev_refthread/dev_relthread should be * called during NVME_BIO_TEST. Ignored for other test * types. */ NVME_TEST_FLAG_REFTHREAD = 0x1, }; struct nvme_pt_command { /* * cmd is used to specify a passthrough command to a controller or * namespace. * * The following fields from cmd may be specified by the caller: * * opc (opcode) * * nsid (namespace id) - for admin commands only * * cdw10-cdw15 * * Remaining fields must be set to 0 by the caller. */ struct nvme_command cmd; /* * cpl returns completion status for the passthrough command * specified by cmd. * * The following fields will be filled out by the driver, for * consumption by the caller: * * cdw0 * * status (except for phase) * * Remaining fields will be set to 0 by the driver. */ struct nvme_completion cpl; /* buf is the data buffer associated with this passthrough command. */ void * buf; /* * len is the length of the data buffer associated with this * passthrough command. */ uint32_t len; /* * is_read = 1 if the passthrough command will read data into the * supplied buffer from the controller. * * is_read = 0 if the passthrough command will write data from the * supplied buffer to the controller. */ uint32_t is_read; /* * driver_lock is used by the driver only. It must be set to 0 * by the caller. */ struct mtx * driver_lock; }; #define nvme_completion_is_error(cpl) \ ((cpl)->status.sc != 0 || (cpl)->status.sct != 0) void nvme_strvis(uint8_t *dst, const uint8_t *src, int dstlen, int srclen); #ifdef _KERNEL struct bio; struct nvme_namespace; struct nvme_controller; struct nvme_consumer; typedef void (*nvme_cb_fn_t)(void *, const struct nvme_completion *); typedef void *(*nvme_cons_ns_fn_t)(struct nvme_namespace *, void *); typedef void *(*nvme_cons_ctrlr_fn_t)(struct nvme_controller *); typedef void (*nvme_cons_async_fn_t)(void *, const struct nvme_completion *, uint32_t, void *, uint32_t); typedef void (*nvme_cons_fail_fn_t)(void *); enum nvme_namespace_flags { NVME_NS_DEALLOCATE_SUPPORTED = 0x1, NVME_NS_FLUSH_SUPPORTED = 0x2, }; int nvme_ctrlr_passthrough_cmd(struct nvme_controller *ctrlr, struct nvme_pt_command *pt, uint32_t nsid, int is_user_buffer, int is_admin_cmd); /* Admin functions */ void nvme_ctrlr_cmd_set_feature(struct nvme_controller *ctrlr, uint8_t feature, uint32_t cdw11, void *payload, uint32_t payload_size, nvme_cb_fn_t cb_fn, void *cb_arg); void nvme_ctrlr_cmd_get_feature(struct nvme_controller *ctrlr, uint8_t feature, uint32_t cdw11, void *payload, uint32_t payload_size, nvme_cb_fn_t cb_fn, void *cb_arg); void nvme_ctrlr_cmd_get_log_page(struct nvme_controller *ctrlr, uint8_t log_page, uint32_t nsid, void *payload, uint32_t payload_size, nvme_cb_fn_t cb_fn, void *cb_arg); /* NVM I/O functions */ int nvme_ns_cmd_write(struct nvme_namespace *ns, void *payload, uint64_t lba, uint32_t lba_count, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_write_bio(struct nvme_namespace *ns, struct bio *bp, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_read(struct nvme_namespace *ns, void *payload, uint64_t lba, uint32_t lba_count, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_read_bio(struct nvme_namespace *ns, struct bio *bp, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_deallocate(struct nvme_namespace *ns, void *payload, uint8_t num_ranges, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_cmd_flush(struct nvme_namespace *ns, nvme_cb_fn_t cb_fn, void *cb_arg); int nvme_ns_dump(struct nvme_namespace *ns, void *virt, off_t offset, size_t len); /* Registration functions */ struct nvme_consumer * nvme_register_consumer(nvme_cons_ns_fn_t ns_fn, nvme_cons_ctrlr_fn_t ctrlr_fn, nvme_cons_async_fn_t async_fn, nvme_cons_fail_fn_t fail_fn); void nvme_unregister_consumer(struct nvme_consumer *consumer); /* Controller helper functions */ device_t nvme_ctrlr_get_device(struct nvme_controller *ctrlr); const struct nvme_controller_data * nvme_ctrlr_get_data(struct nvme_controller *ctrlr); /* Namespace helper functions */ uint32_t nvme_ns_get_max_io_xfer_size(struct nvme_namespace *ns); uint32_t nvme_ns_get_sector_size(struct nvme_namespace *ns); uint64_t nvme_ns_get_num_sectors(struct nvme_namespace *ns); uint64_t nvme_ns_get_size(struct nvme_namespace *ns); uint32_t nvme_ns_get_flags(struct nvme_namespace *ns); const char * nvme_ns_get_serial_number(struct nvme_namespace *ns); const char * nvme_ns_get_model_number(struct nvme_namespace *ns); const struct nvme_namespace_data * nvme_ns_get_data(struct nvme_namespace *ns); uint32_t nvme_ns_get_stripesize(struct nvme_namespace *ns); int nvme_ns_bio_process(struct nvme_namespace *ns, struct bio *bp, nvme_cb_fn_t cb_fn); /* Command building helper functions -- shared with CAM */ static inline void nvme_ns_flush_cmd(struct nvme_command *cmd, uint16_t nsid) { cmd->opc = NVME_OPC_FLUSH; cmd->nsid = nsid; } static inline void nvme_ns_rw_cmd(struct nvme_command *cmd, uint32_t rwcmd, uint16_t nsid, uint64_t lba, uint32_t count) { cmd->opc = rwcmd; cmd->nsid = nsid; *(uint64_t *)&cmd->cdw10 = lba; cmd->cdw12 = count-1; cmd->cdw13 = 0; cmd->cdw14 = 0; cmd->cdw15 = 0; } static inline void nvme_ns_write_cmd(struct nvme_command *cmd, uint16_t nsid, uint64_t lba, uint32_t count) { nvme_ns_rw_cmd(cmd, NVME_OPC_WRITE, nsid, lba, count); } static inline void nvme_ns_read_cmd(struct nvme_command *cmd, uint16_t nsid, uint64_t lba, uint32_t count) { nvme_ns_rw_cmd(cmd, NVME_OPC_READ, nsid, lba, count); } static inline void nvme_ns_trim_cmd(struct nvme_command *cmd, uint16_t nsid, uint32_t num_ranges) { cmd->opc = NVME_OPC_DATASET_MANAGEMENT; cmd->nsid = nsid; cmd->cdw10 = num_ranges - 1; cmd->cdw11 = NVME_DSM_ATTR_DEALLOCATE; } #endif /* _KERNEL */ #endif /* __NVME_H__ */ Index: projects/clang390-import/sys/mips/atheros/ar531x/files.ar5315 =================================================================== --- projects/clang390-import/sys/mips/atheros/ar531x/files.ar5315 (revision 308867) +++ projects/clang390-import/sys/mips/atheros/ar531x/files.ar5315 (revision 308868) @@ -1,31 +1,22 @@ # $FreeBSD$ mips/atheros/ar531x/apb.c standard mips/atheros/ar531x/if_are.c optional are mips/atheros/ar531x/ar5315_spi.c optional ar5315_spi mips/atheros/ar531x/ar5315_wdog.c optional ar5315_wdog mips/atheros/ar531x/ar5315_gpio.c optional gpio mips/atheros/ar531x/ar5315_machdep.c standard mips/atheros/ar531x/ar5315_chip.c standard mips/atheros/ar531x/ar5315_setup.c standard mips/atheros/ar531x/uart_bus_ar5315.c optional uart_ar5315 mips/atheros/ar531x/uart_cpu_ar5315.c optional uart_ar5315 mips/atheros/ar531x/ar5312_chip.c standard mips/atheros/ar71xx_bus_space_reversed.c standard mips/mips/tick.c standard dev/etherswitch/e6000sw/e6060sw.c optional etherswitch -# Hack to reuse ARM intrng code -kern/subr_intr.c optional intrng -kern/msi_if.m optional intrng -kern/pic_if.m optional intrng - -# Intrng compatible MIPS32 interrupt controller -mips/mips/mips_pic.c optional intrng - # Non Intrng mips/mips/intr_machdep.c optional !intrng - Index: projects/clang390-import/sys/mips/broadcom/files.broadcom =================================================================== --- projects/clang390-import/sys/mips/broadcom/files.broadcom (revision 308867) +++ projects/clang390-import/sys/mips/broadcom/files.broadcom (revision 308868) @@ -1,27 +1,22 @@ # $FreeBSD$ # TODO: Add attachment elsewhere in the tree # for USB 1.1 OHCI, Ethernet and IPSEC cores # which are believed to be devices we have drivers for # which just need to be tweaked for attachment to an BHND system bus. mips/broadcom/bcm_machdep.c standard mips/broadcom/bcm_bmips.c optional siba_nexus siba mips/broadcom/bcm_mips74k.c optional bcma_nexus bcma mips/broadcom/bcm_pmu.c standard mips/mips/tick.c standard -mips/mips/mips_pic.c standard -kern/subr_intr.c standard -kern/pic_if.m standard - -kern/msi_if.m optional intrng mips/broadcom/uart_cpu_chipc.c optional uart mips/broadcom/uart_bus_chipc.c optional uart # TODO: Replace with BCM47xx/57xx/etc-aware geom_map geom/geom_flashmap.c standard # USB bits dev/bhnd/cores/usb/bhnd_usb.c optional usb dev/bhnd/cores/usb/bhnd_ehci.c optional ehci dev/bhnd/cores/usb/bhnd_ohci.c optional ohci Index: projects/clang390-import/sys/mips/conf/CANNA =================================================================== --- projects/clang390-import/sys/mips/conf/CANNA (nonexistent) +++ projects/clang390-import/sys/mips/conf/CANNA (revision 308868) @@ -0,0 +1,29 @@ +# CANNA -- Kernel config for Ingenic CANNA board +# +# $FreeBSD$ + +include "X1000" +ident CANNA + +options FDT +options FDT_DTB_STATIC +makeoptions FDT_DTS_FILE=ingenic/canna.dts + +#options KTR +#options KTR_CPUMASK=0x3 +#options KTR_MASK=(KTR_GEN) +#options KTR_COMPILE=(KTR_GEN) +#options KTR_VERBOSE + +# Uncomment for NFS root +#options BOOTP +#options BOOTP_NFSROOT +#options BOOTP_NFSV3 +#options BOOTP_WIRED_TO=dme0 +#options BOOTP_COMPAT +options ROOTDEVNAME=\"ufs:mmcsd0s3\" + +makeoptions TRAMPLOADADDR=0x88000000 + +#options VERBOSE_SYSINIT +options PRINTF_BUFR_SIZE=256 Property changes on: projects/clang390-import/sys/mips/conf/CANNA ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/conf/CI20 =================================================================== --- projects/clang390-import/sys/mips/conf/CI20 (nonexistent) +++ projects/clang390-import/sys/mips/conf/CI20 (revision 308868) @@ -0,0 +1,31 @@ +# CI20 -- Kernel config for Creator CI20 board +# +# $FreeBSD$ + +include "JZ4780" +ident CI20 + +options FDT +options FDT_DTB_STATIC +makeoptions FDT_DTS_FILE=ingenic/ci20.dts + +#options KTR +#options KTR_CPUMASK=0x3 +#options KTR_MASK=(KTR_GEN) +#options KTR_COMPILE=(KTR_GEN) +#options KTR_VERBOSE + +# Uncomment for NFS root +#options BOOTP +#options BOOTP_NFSROOT +#options BOOTP_NFSV3 +#options BOOTP_WIRED_TO=dme0 +#options BOOTP_COMPAT + +options ROOTDEVNAME=\"ufs:mmcsd0\" + +makeoptions TRAMPLOADADDR=0x88000000 + +#options VERBOSE_SYSINIT +device dme +options PRINTF_BUFR_SIZE=256 Property changes on: projects/clang390-import/sys/mips/conf/CI20 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/conf/JZ4780 =================================================================== --- projects/clang390-import/sys/mips/conf/JZ4780 (nonexistent) +++ projects/clang390-import/sys/mips/conf/JZ4780 (revision 308868) @@ -0,0 +1,92 @@ +# JZ4780 -- Kernel config for Ingenic JZ47XX boards +# +# $FreeBSD$ + +ident JZ4780 +machine mips mipsel +cpu CPU_XBURST +cpu CPU_MIPS4KC + +makeoptions KERNLOADADDR=0x80020000 +makeoptions ARCH_FLAGS="-EL -march=mips32r2" + +# Don't build any modules yet. +makeoptions MODULES_OVERRIDE="" + +files "../ingenic/files.jz4780" +hints "JZ4780.hints" #Default places to look for devices. + +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols + +options INTRNG # Borrow interrupt code from ARM +options MIPS_NIRQ=264 # 8 cpuintc + 64 intc + 6 * 23 gpio + +options DDB +options KDB +options BREAK_TO_DEBUGGER + +options COMPAT_FREEBSD10 + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +options NFSCL #Network Filesystem Client +options NFS_ROOT #NFS usable as /, requires NFSCL +options NFSLOCKD #Network Lock Manager +options PSEUDOFS #Pseudo-filesystem framework +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions + +options FFS #Berkeley Fast Filesystem +options SOFTUPDATES #Enable FFS soft updates support +options UFS_ACL #Support for access control lists +options UFS_DIRHASH #Improve performance on big directories +#options ROOTDEVNAME=\"ufs:ada0\" + +options GEOM_LABEL # Provides labelization +options GEOM_PART_GPT # GUID Partition Tables. +#options GEOM_RAID # Soft RAID functionality. + +# Debugging for use in -current +#options DEADLKRES #Enable the deadlock resolver +options INVARIANTS #Enable calls of extra sanity checking +options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed + +# Make an SMP-capable kernel by default +options SMP # Symmetric MultiProcessor Kernel + +device loop +device ether +#device le +device miibus +device bpf +device md +device uart +device random + +device fdt_pinctrl + +device clk +device regulator +device ext_resources + +device gpio + +device scbus +device da + +device mmc +device mmcsd + +# USB support +options USB_DEBUG # enable debug msgs +options USB_HOST_ALIGN=128 # L2 cache line size +device ohci # OHCI PCI->USB interface +device ehci # EHCI PCI->USB interface (USB 2.0) +device dwcotg # DesignWare HS OTG controller +device usb # USB Bus (required) +#device udbp # USB Double Bulk Pipe devices +device uhid # "Human Interface Devices" +#device ulpt # Printer +device umass # Disks/Mass storage - Requires scbus and da +device ums # Mouse Property changes on: projects/clang390-import/sys/mips/conf/JZ4780 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/conf/JZ4780.hints =================================================================== --- projects/clang390-import/sys/mips/conf/JZ4780.hints (nonexistent) +++ projects/clang390-import/sys/mips/conf/JZ4780.hints (revision 308868) @@ -0,0 +1,2 @@ +# $FreeBSD$ +# device.hints Property changes on: projects/clang390-import/sys/mips/conf/JZ4780.hints ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/conf/X1000 =================================================================== --- projects/clang390-import/sys/mips/conf/X1000 (nonexistent) +++ projects/clang390-import/sys/mips/conf/X1000 (revision 308868) @@ -0,0 +1,89 @@ +# X1000 -- Kernel config for Ingenic X1000 boards +# +# $FreeBSD$ + +ident X1000 +machine mips mipsel +cpu CPU_XBURST +cpu CPU_MIPS4KC + +makeoptions KERNLOADADDR=0x80020000 +makeoptions ARCH_FLAGS="-EL -march=mips32r2" + +# Don't build any modules yet. +makeoptions MODULES_OVERRIDE="" + +files "../ingenic/files.x1000" +hints "X1000.hints" #Default places to look for devices. + +makeoptions DEBUG=-g #Build kernel with gdb(1) debug symbols + +options INTRNG # Borrow interrupt code from ARM +options MIPS_NIRQ=264 # 8 cpuintc + 64 intc + 6 * 23 gpio + +options DDB +options KDB +options BREAK_TO_DEBUGGER + +options COMPAT_FREEBSD10 + +options SCHED_4BSD #4BSD scheduler +options INET #InterNETworking +options NFSCL #Network Filesystem Client +options NFS_ROOT #NFS usable as /, requires NFSCL +options NFSLOCKD #Network Lock Manager +options PSEUDOFS #Pseudo-filesystem framework +options _KPOSIX_PRIORITY_SCHEDULING #Posix P1003_1B real-time extensions + +options FFS #Berkeley Fast Filesystem +options SOFTUPDATES #Enable FFS soft updates support +options UFS_ACL #Support for access control lists +options UFS_DIRHASH #Improve performance on big directories +#options ROOTDEVNAME=\"ufs:ada0\" + +options GEOM_LABEL # Provides labelization +options GEOM_PART_GPT # GUID Partition Tables. +#options GEOM_RAID # Soft RAID functionality. + +# Debugging for use in -current +#options DEADLKRES #Enable the deadlock resolver +options INVARIANTS #Enable calls of extra sanity checking +options INVARIANT_SUPPORT #Extra sanity checks of internal structures, required by INVARIANTS +#options WITNESS #Enable checks to detect deadlocks and cycles +#options WITNESS_SKIPSPIN #Don't run witness on spinlocks for speed + +device loop +device ether +#device le +device miibus +device bpf +device md +device uart +device random + +device fdt_pinctrl + +device clk +device regulator +device ext_resources + +device gpio + +device scbus +device da + +device mmc +device mmcsd + +# USB support +#options USB_DEBUG # enable debug msgs +#options USB_HOST_ALIGN=128 # L2 cache line size +#device ohci # OHCI PCI->USB interface +#device ehci # EHCI PCI->USB interface (USB 2.0) +#device dwcotg # DesignWare HS OTG controller +#device usb # USB Bus (required) +#device udbp # USB Double Bulk Pipe devices +#device uhid # "Human Interface Devices" +#device ulpt # Printer +#device umass # Disks/Mass storage - Requires scbus and da +#device ums # Mouse Property changes on: projects/clang390-import/sys/mips/conf/X1000 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/conf/X1000.hints =================================================================== --- projects/clang390-import/sys/mips/conf/X1000.hints (nonexistent) +++ projects/clang390-import/sys/mips/conf/X1000.hints (revision 308868) @@ -0,0 +1,2 @@ +# $FreeBSD$ +# device.hints Property changes on: projects/clang390-import/sys/mips/conf/X1000.hints ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/include/cache.h =================================================================== --- projects/clang390-import/sys/mips/include/cache.h (revision 308867) +++ projects/clang390-import/sys/mips/include/cache.h (revision 308868) @@ -1,222 +1,224 @@ /* $NetBSD: cache.h,v 1.6 2003/02/17 11:35:01 simonb Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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. * * $FreeBSD$ */ #ifndef _MACHINE_CACHE_H_ #define _MACHINE_CACHE_H_ /* * Cache operations. * * We define the following primitives: * * --- Instruction cache synchronization (mandatory): * * icache_sync_all Synchronize I-cache * * icache_sync_range Synchronize I-cache range * * icache_sync_range_index (index ops) * * --- Primary data cache (mandatory): * * pdcache_wbinv_all Write-back Invalidate primary D-cache * * pdcache_wbinv_range Write-back Invalidate primary D-cache range * * pdcache_wbinv_range_index (index ops) * * pdcache_inv_range Invalidate primary D-cache range * * pdcache_wb_range Write-back primary D-cache range * * --- Secondary data cache (optional): * * sdcache_wbinv_all Write-back Invalidate secondary D-cache * * sdcache_wbinv_range Write-back Invalidate secondary D-cache range * * sdcache_wbinv_range_index (index ops) * * sdcache_inv_range Invalidate secondary D-cache range * * sdcache_wb_range Write-back secondary D-cache range * * There are some rules that must be followed: * * I-cache Synch (all or range): * The goal is to synchronize the instruction stream, * so you may need to write-back dirty data cache * blocks first. If a range is requested, and you * can't synchronize just a range, you have to hit * the whole thing. * * D-cache Write-back Invalidate range: * If you can't WB-Inv a range, you must WB-Inv the * entire D-cache. * * D-cache Invalidate: * If you can't Inv the D-cache without doing a * Write-back, YOU MUST PANIC. This is to catch * errors in calling code. Callers must be aware * of this scenario, and must handle it appropriately * (consider the bus_dma(9) operations). * * D-cache Write-back: * If you can't Write-back without doing an invalidate, * that's fine. Then treat this as a WB-Inv. Skipping * the invalidate is merely an optimization. * * All operations: * Valid virtual addresses must be passed to the * cache operation. * * Finally, these primitives are grouped together in reasonable * ways. For all operations described here, first the primary * cache is frobbed, then the secondary cache frobbed, if the * operation for the secondary cache exists. * * mips_icache_sync_all Synchronize I-cache * * mips_icache_sync_range Synchronize I-cache range * * mips_icache_sync_range_index (index ops) * * mips_dcache_wbinv_all Write-back Invalidate D-cache * * mips_dcache_wbinv_range Write-back Invalidate D-cache range * * mips_dcache_wbinv_range_index (index ops) * * mips_dcache_inv_range Invalidate D-cache range * * mips_dcache_wb_range Write-back D-cache range */ struct mips_cache_ops { void (*mco_icache_sync_all)(void); void (*mco_icache_sync_range)(vm_offset_t, vm_size_t); void (*mco_icache_sync_range_index)(vm_offset_t, vm_size_t); void (*mco_pdcache_wbinv_all)(void); void (*mco_pdcache_wbinv_range)(vm_offset_t, vm_size_t); void (*mco_pdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_pdcache_inv_range)(vm_offset_t, vm_size_t); void (*mco_pdcache_wb_range)(vm_offset_t, vm_size_t); /* These are called only by the (mipsNN) icache functions. */ void (*mco_intern_pdcache_wbinv_all)(void); void (*mco_intern_pdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_intern_pdcache_wb_range)(vm_offset_t, vm_size_t); void (*mco_sdcache_wbinv_all)(void); void (*mco_sdcache_wbinv_range)(vm_offset_t, vm_size_t); void (*mco_sdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_sdcache_inv_range)(vm_offset_t, vm_size_t); void (*mco_sdcache_wb_range)(vm_offset_t, vm_size_t); /* These are called only by the (mipsNN) icache functions. */ void (*mco_intern_sdcache_wbinv_all)(void); void (*mco_intern_sdcache_wbinv_range_index)(vm_offset_t, vm_size_t); void (*mco_intern_sdcache_wb_range)(vm_offset_t, vm_size_t); }; extern struct mips_cache_ops mips_cache_ops; /* PRIMARY CACHE VARIABLES */ extern int mips_picache_linesize; extern int mips_pdcache_linesize; +extern int mips_sdcache_linesize; +extern int mips_dcache_max_linesize; #define __mco_noargs(prefix, x) \ do { \ (*mips_cache_ops.mco_ ## prefix ## p ## x )(); \ if (*mips_cache_ops.mco_ ## prefix ## s ## x ) \ (*mips_cache_ops.mco_ ## prefix ## s ## x )(); \ } while (/*CONSTCOND*/0) #define __mco_2args(prefix, x, a, b) \ do { \ (*mips_cache_ops.mco_ ## prefix ## p ## x )((a), (b)); \ if (*mips_cache_ops.mco_ ## prefix ## s ## x ) \ (*mips_cache_ops.mco_ ## prefix ## s ## x )((a), (b)); \ } while (/*CONSTCOND*/0) #define mips_icache_sync_all() \ (*mips_cache_ops.mco_icache_sync_all)() #define mips_icache_sync_range(v, s) \ (*mips_cache_ops.mco_icache_sync_range)((v), (s)) #define mips_icache_sync_range_index(v, s) \ (*mips_cache_ops.mco_icache_sync_range_index)((v), (s)) #define mips_dcache_wbinv_all() \ __mco_noargs(, dcache_wbinv_all) #define mips_dcache_wbinv_range(v, s) \ __mco_2args(, dcache_wbinv_range, (v), (s)) #define mips_dcache_wbinv_range_index(v, s) \ __mco_2args(, dcache_wbinv_range_index, (v), (s)) #define mips_dcache_inv_range(v, s) \ __mco_2args(, dcache_inv_range, (v), (s)) #define mips_dcache_wb_range(v, s) \ __mco_2args(, dcache_wb_range, (v), (s)) /* * Private D-cache functions only called from (currently only the * mipsNN) I-cache functions. */ #define mips_intern_dcache_wbinv_all() \ __mco_noargs(intern_, dcache_wbinv_all) #define mips_intern_dcache_wbinv_range_index(v, s) \ __mco_2args(intern_, dcache_wbinv_range_index, (v), (s)) #define mips_intern_dcache_wb_range(v, s) \ __mco_2args(intern_, dcache_wb_range, (v), (s)) /* forward declaration */ struct mips_cpuinfo; void mips_config_cache(struct mips_cpuinfo *); #include #endif /* _MACHINE_CACHE_H_ */ Index: projects/clang390-import/sys/mips/ingenic/files.jz4780 =================================================================== --- projects/clang390-import/sys/mips/ingenic/files.jz4780 (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/files.jz4780 (revision 308868) @@ -0,0 +1,26 @@ +# $FreeBSD$ + +mips/ingenic/jz4780_dwc_fdt.c optional dwcotg +mips/ingenic/jz4780_ehci.c optional ehci +mips/ingenic/jz4780_mmc.c optional mmc +mips/ingenic/jz4780_ohci.c optional ohci +mips/ingenic/jz4780_uart.c optional uart + +mips/ingenic/jz4780_clock.c standard +mips/ingenic/jz4780_clk_gen.c standard +mips/ingenic/jz4780_clk_otg.c standard +mips/ingenic/jz4780_clk_pll.c standard +mips/ingenic/jz4780_efuse.c standard +mips/ingenic/jz4780_intr.c standard +mips/ingenic/jz4780_gpio.c standard +mips/ingenic/jz4780_machdep.c standard +mips/ingenic/jz4780_nemc.c standard +mips/ingenic/jz4780_pinctrl.c standard +mips/ingenic/jz4780_timer.c standard + +# SMP +mips/ingenic/jz4780_mp.c optional smp +mips/ingenic/jz4780_mpboot.S optional smp + +# Custom interface between pinctrl and gpio +mips/ingenic/jz4780_gpio_if.m standard Property changes on: projects/clang390-import/sys/mips/ingenic/files.jz4780 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/files.x1000 =================================================================== --- projects/clang390-import/sys/mips/ingenic/files.x1000 (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/files.x1000 (revision 308868) @@ -0,0 +1,17 @@ +# $FreeBSD$ + +mips/ingenic/jz4780_mmc.c optional mmc +mips/ingenic/jz4780_uart.c optional uart + +mips/ingenic/jz4780_clock.c standard +mips/ingenic/jz4780_clk_gen.c standard +mips/ingenic/jz4780_clk_otg.c standard +mips/ingenic/jz4780_clk_pll.c standard +mips/ingenic/jz4780_intr.c standard +mips/ingenic/jz4780_gpio.c standard +mips/ingenic/jz4780_machdep.c standard +mips/ingenic/jz4780_pinctrl.c standard +mips/ingenic/jz4780_timer.c standard + +# Custom interface between pinctrl and gpio +mips/ingenic/jz4780_gpio_if.m standard Property changes on: projects/clang390-import/sys/mips/ingenic/files.x1000 ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_clk.h =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_clk.h (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_clk.h (revision 308868) @@ -0,0 +1,93 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + * + * $FreeBSD$ + */ + +#ifndef _MIPS_INGENIC_JZ4780_CLK_H +#define _MIPS_INGENIC_JZ4780_CLK_H + +#include +#include + +/* Convenience bitfiled manipulation macros */ +#define REG_MSK(field) (((1u << field ## _WIDTH) - 1) << field ##_SHIFT) +#define REG_VAL(field, val) ((val) << field ##_SHIFT) +#define REG_CLR(reg, field) ((reg) & ~REG_MSK(field)) +#define REG_GET(reg, field) (((reg) & REG_MSK(field)) >> field ##_SHIFT) +#define REG_SET(reg, field, val) (REG_CLR(reg, field) | REG_VAL(field, val)) + +/* Common clock macros */ +#define CLK_LOCK(_sc) mtx_lock((_sc)->clk_mtx) +#define CLK_UNLOCK(_sc) mtx_unlock((_sc)->clk_mtx) + +#define CLK_WR_4(_sc, off, val) bus_write_4((_sc)->clk_res, (off), (val)) +#define CLK_RD_4(_sc, off) bus_read_4((_sc)->clk_res, (off)) + +struct jz4780_clk_mux_descr { + uint16_t mux_reg; + uint16_t mux_shift: 5; + uint16_t mux_bits: 5; + uint16_t mux_map: 4; /* Map into mux space */ +}; + +struct jz4780_clk_div_descr { + uint16_t div_reg; + uint16_t div_shift: 5; + uint16_t div_bits: 5; + uint16_t div_lg: 5; + int div_ce_bit: 6; /* -1, if CE bit is not present */ + int div_st_bit: 6; /* Can be negative */ + int div_busy_bit: 6; /* Can be negative */ +}; + +struct jz4780_clk_descr { + uint16_t clk_id: 6; + uint16_t clk_type: 3; + int clk_gate_bit: 7; /* Can be negative */ + struct jz4780_clk_mux_descr clk_mux; + struct jz4780_clk_div_descr clk_div; + const char *clk_name; + const char *clk_pnames[4]; +}; + +/* clk_type bits */ +#define CLK_MASK_GATE 0x01 +#define CLK_MASK_DIV 0x02 +#define CLK_MASK_MUX 0x04 + +extern int jz4780_clk_gen_register(struct clkdom *clkdom, + const struct jz4780_clk_descr *descr, struct mtx *dev_mtx, + struct resource *mem_res); + +extern int jz4780_clk_pll_register(struct clkdom *clkdom, + struct clknode_init_def *clkdef, struct mtx *dev_mtx, + struct resource *mem_res, uint32_t mem_reg); + +extern int jz4780_clk_otg_register(struct clkdom *clkdom, + struct clknode_init_def *clkdef, struct mtx *dev_mtx, + struct resource *mem_res); + +#endif /* _MIPS_INGENIC_JZ4780_CLK_PLL_H */ Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_clk.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_clk_gen.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_clk_gen.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_clk_gen.c (revision 308868) @@ -0,0 +1,317 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + */ + +/* + * Ingenic JZ4780 generic CGU clock driver. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* JZ4780 generic mux and div clocks implementation */ +static int jz4780_clk_gen_init(struct clknode *clk, device_t dev); +static int jz4780_clk_gen_recalc_freq(struct clknode *clk, uint64_t *freq); +static int jz4780_clk_gen_set_freq(struct clknode *clk, uint64_t fin, + uint64_t *fout, int flags, int *stop); +static int jz4780_clk_gen_set_gate(struct clknode *clk, bool enable); +static int jz4780_clk_gen_set_mux(struct clknode *clk, int src); + +struct jz4780_clk_gen_sc { + struct mtx *clk_mtx; + struct resource *clk_res; + int clk_reg; + const struct jz4780_clk_descr *clk_descr; +}; + +/* + * JZ4780 clock PLL clock methods + */ +static clknode_method_t jz4780_clk_gen_methods[] = { + CLKNODEMETHOD(clknode_init, jz4780_clk_gen_init), + CLKNODEMETHOD(clknode_set_gate, jz4780_clk_gen_set_gate), + CLKNODEMETHOD(clknode_recalc_freq, jz4780_clk_gen_recalc_freq), + CLKNODEMETHOD(clknode_set_freq, jz4780_clk_gen_set_freq), + CLKNODEMETHOD(clknode_set_mux, jz4780_clk_gen_set_mux), + + CLKNODEMETHOD_END +}; +DEFINE_CLASS_1(jz4780_clk_pll, jz4780_clk_gen_class, jz4780_clk_gen_methods, + sizeof(struct jz4780_clk_gen_sc), clknode_class); + +static inline unsigned +mux_to_reg(unsigned src, unsigned map) +{ + unsigned ret, bit; + + bit = (1u << 3); + for (ret = 0; bit; ret++, bit >>= 1) { + if (map & bit) { + if (src-- == 0) + return (ret); + } + } + panic("mux_to_reg"); +} + +static inline unsigned +reg_to_mux(unsigned reg, unsigned map) +{ + unsigned ret, bit; + + bit = (1u << 3); + for (ret = 0; reg; reg--, bit >>= 1) + if (map & bit) + ret++; + return (ret); +} + +static int +jz4780_clk_gen_init(struct clknode *clk, device_t dev) +{ + struct jz4780_clk_gen_sc *sc; + uint32_t reg, msk, parent_idx; + + sc = clknode_get_softc(clk); + CLK_LOCK(sc); + /* Figure our parent out */ + if (sc->clk_descr->clk_type & CLK_MASK_MUX) { + msk = (1u << sc->clk_descr->clk_mux.mux_bits) - 1; + reg = CLK_RD_4(sc, sc->clk_descr->clk_mux.mux_reg); + reg = (reg >> sc->clk_descr->clk_mux.mux_shift) & msk; + parent_idx = reg_to_mux(reg, sc->clk_descr->clk_mux.mux_map); + } else + parent_idx = 0; + CLK_UNLOCK(sc); + + clknode_init_parent_idx(clk, parent_idx); + return (0); +} + +static int +jz4780_clk_gen_recalc_freq(struct clknode *clk, uint64_t *freq) +{ + struct jz4780_clk_gen_sc *sc; + uint32_t reg; + + sc = clknode_get_softc(clk); + + /* Calculate divisor frequency */ + if (sc->clk_descr->clk_type & CLK_MASK_DIV) { + uint32_t msk; + + msk = (1u << sc->clk_descr->clk_div.div_bits) - 1; + reg = CLK_RD_4(sc, sc->clk_descr->clk_div.div_reg); + reg = (reg >> sc->clk_descr->clk_div.div_shift) & msk; + reg = (reg + 1) << sc->clk_descr->clk_div.div_lg; + *freq /= reg; + } + return (0); +} + +#define DIV_TIMEOUT 100 + +static int +jz4780_clk_gen_set_freq(struct clknode *clk, uint64_t fin, + uint64_t *fout, int flags, int *stop) +{ + struct jz4780_clk_gen_sc *sc; + uint64_t _fout; + uint32_t divider, div_reg, div_msk, reg; + int rv; + + sc = clknode_get_softc(clk); + + divider = fin / *fout; + + /* Adjust for divider multiplier */ + div_reg = divider >> sc->clk_descr->clk_div.div_lg; + divider = div_reg << sc->clk_descr->clk_div.div_lg; + + _fout = fin / divider; + + /* Rounding */ + if ((flags & CLK_SET_ROUND_UP) && (*fout < _fout)) + div_reg--; + else if ((flags & CLK_SET_ROUND_DOWN) && (*fout > _fout)) + div_reg++; + if (div_reg == 0) + div_reg = 1; + + div_msk = (1u << sc->clk_descr->clk_div.div_bits) - 1; + + *stop = 1; + if (div_reg > div_msk + 1) { + *stop = 0; + div_reg = div_msk; + } + + divider = (div_reg << sc->clk_descr->clk_div.div_lg); + div_reg--; + + if ((flags & CLK_SET_DRYRUN) != 0) { + if (*stop != 0 && *fout != fin / divider && + (flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) + return (ERANGE); + *fout = fin / divider; + return (0); + } + + CLK_LOCK(sc); + /* Apply the new divider value */ + reg = CLK_RD_4(sc, sc->clk_descr->clk_div.div_reg); + reg &= ~(div_msk << sc->clk_descr->clk_div.div_shift); + reg |= (div_reg << sc->clk_descr->clk_div.div_shift); + /* Set the change enable bit, it present */ + if (sc->clk_descr->clk_div.div_ce_bit >= 0) + reg |= (1u << sc->clk_descr->clk_div.div_ce_bit); + /* Clear stop bit, it present */ + if (sc->clk_descr->clk_div.div_st_bit >= 0) + reg &= ~(1u << sc->clk_descr->clk_div.div_st_bit); + /* Initiate the change */ + CLK_WR_4(sc, sc->clk_descr->clk_div.div_reg, reg); + + /* Wait for busy bit to clear indicating the change is complete */ + rv = 0; + if (sc->clk_descr->clk_div.div_busy_bit >= 0) { + int i; + + for (i = 0; i < DIV_TIMEOUT; i++) { + reg = CLK_RD_4(sc, sc->clk_descr->clk_div.div_reg); + if (!(reg & (1u << sc->clk_descr->clk_div.div_busy_bit))) + break; + DELAY(1000); + } + if (i == DIV_TIMEOUT) + rv = ETIMEDOUT; + } + CLK_UNLOCK(sc); + + *fout = fin / divider; + return (rv); +} + +static int +jz4780_clk_gen_set_mux(struct clknode *clk, int src) +{ + struct jz4780_clk_gen_sc *sc; + uint32_t reg, msk; + + sc = clknode_get_softc(clk); + + /* Only mux nodes are capable of being reparented */ + if (!(sc->clk_descr->clk_type & CLK_MASK_MUX)) + return (src ? EINVAL : 0); + + msk = (1u << sc->clk_descr->clk_mux.mux_bits) - 1; + src = mux_to_reg(src & msk, sc->clk_descr->clk_mux.mux_map); + + CLK_LOCK(sc); + reg = CLK_RD_4(sc, sc->clk_descr->clk_mux.mux_reg); + reg &= ~(msk << sc->clk_descr->clk_mux.mux_shift); + reg |= (src << sc->clk_descr->clk_mux.mux_shift); + CLK_WR_4(sc, sc->clk_descr->clk_mux.mux_reg, reg); + CLK_UNLOCK(sc); + + return (0); +} + +static int +jz4780_clk_gen_set_gate(struct clknode *clk, bool enable) +{ + struct jz4780_clk_gen_sc *sc; + uint32_t off, reg, bit; + + sc = clknode_get_softc(clk); + + /* Check is clock can be gated */ + if (sc->clk_descr->clk_gate_bit < 0) + return 0; + + bit = sc->clk_descr->clk_gate_bit; + if (bit < 32) { + off = JZ_CLKGR0; + } else { + off = JZ_CLKGR1; + bit -= 32; + } + + CLK_LOCK(sc); + reg = CLK_RD_4(sc, off); + if (enable) + reg &= ~(1u << bit); + else + reg |= (1u << bit); + CLK_WR_4(sc, off, reg); + CLK_UNLOCK(sc); + + return (0); +} + + +int jz4780_clk_gen_register(struct clkdom *clkdom, + const struct jz4780_clk_descr *descr, struct mtx *dev_mtx, + struct resource *mem_res) +{ + struct clknode_init_def clkdef; + struct clknode *clk; + struct jz4780_clk_gen_sc *sc; + + clkdef.id = descr->clk_id; + clkdef.name = __DECONST(char *, descr->clk_name); + /* Silly const games to work around API deficiency */ + clkdef.parent_names = (const char **)(uintptr_t)&descr->clk_pnames[0]; + clkdef.flags = CLK_NODE_STATIC_STRINGS; + if (descr->clk_type & CLK_MASK_MUX) + clkdef.parent_cnt = __bitcount16(descr->clk_mux.mux_map); + else + clkdef.parent_cnt = 1; + + clk = clknode_create(clkdom, &jz4780_clk_gen_class, &clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + sc->clk_mtx = dev_mtx; + sc->clk_res = mem_res; + sc->clk_descr = descr; + clknode_register(clkdom, clk); + + return (0); +} Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_clk_gen.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_clk_otg.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_clk_otg.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_clk_otg.c (revision 308868) @@ -0,0 +1,167 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + */ + +/* + * Ingenic JZ4780 OTG PHY clock driver. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +/* JZ4780 OTG PHY clock */ +static int jz4780_clk_otg_init(struct clknode *clk, device_t dev); +static int jz4780_clk_otg_recalc_freq(struct clknode *clk, uint64_t *freq); +static int jz4780_clk_otg_set_freq(struct clknode *clk, uint64_t fin, + uint64_t *fout, int flags, int *stop); + +struct jz4780_clk_otg_sc { + struct mtx *clk_mtx; + struct resource *clk_res; +}; + +/* + * JZ4780 OTG PHY clock methods + */ +static clknode_method_t jz4780_clk_otg_methods[] = { + CLKNODEMETHOD(clknode_init, jz4780_clk_otg_init), + CLKNODEMETHOD(clknode_recalc_freq, jz4780_clk_otg_recalc_freq), + CLKNODEMETHOD(clknode_set_freq, jz4780_clk_otg_set_freq), + + CLKNODEMETHOD_END +}; +DEFINE_CLASS_1(jz4780_clk_pll, jz4780_clk_otg_class, jz4780_clk_otg_methods, + sizeof(struct jz4780_clk_otg_sc), clknode_class); + +static int +jz4780_clk_otg_init(struct clknode *clk, device_t dev) +{ + struct jz4780_clk_otg_sc *sc; + uint32_t reg; + + sc = clknode_get_softc(clk); + CLK_LOCK(sc); + /* Force the use fo the core clock */ + reg = CLK_RD_4(sc, JZ_USBPCR1); + reg &= ~PCR_REFCLK_M; + reg |= PCR_REFCLK_CORE; + CLK_WR_4(sc, JZ_USBPCR1, reg); + CLK_UNLOCK(sc); + + clknode_init_parent_idx(clk, 0); + return (0); +} + +static const struct { + uint32_t div_val; + uint32_t freq; +} otg_div_table[] = { + { PCR_CLK_12, 12000000 }, + { PCR_CLK_192, 19200000 }, + { PCR_CLK_24, 24000000 }, + { PCR_CLK_48, 48000000 } +}; + +static int +jz4780_clk_otg_recalc_freq(struct clknode *clk, uint64_t *freq) +{ + struct jz4780_clk_otg_sc *sc; + uint32_t reg; + int i; + + sc = clknode_get_softc(clk); + reg = CLK_RD_4(sc, JZ_USBPCR1); + reg &= PCR_CLK_M; + + for (i = 0; i < nitems(otg_div_table); i++) + if (otg_div_table[i].div_val == reg) + *freq = otg_div_table[i].freq; + return (0); +} + +static int +jz4780_clk_otg_set_freq(struct clknode *clk, uint64_t fin, + uint64_t *fout, int flags, int *stop) +{ + struct jz4780_clk_otg_sc *sc; + uint32_t reg; + int i; + + sc = clknode_get_softc(clk); + + for (i = 0; i < nitems(otg_div_table) - 1; i++) { + if (*fout < (otg_div_table[i].freq + otg_div_table[i + 1].freq) / 2) + break; + } + + *fout = otg_div_table[i].freq; + + *stop = 1; + if (flags & CLK_SET_DRYRUN) + return (0); + + CLK_LOCK(sc); + reg = CLK_RD_4(sc, JZ_USBPCR1); + /* Set the calculated values */ + reg &= ~PCR_CLK_M; + reg |= otg_div_table[i].div_val; + /* Initiate the change */ + CLK_WR_4(sc, JZ_USBPCR1, reg); + CLK_UNLOCK(sc); + + return (0); +} + +int jz4780_clk_otg_register(struct clkdom *clkdom, + struct clknode_init_def *clkdef, struct mtx *dev_mtx, + struct resource *mem_res) +{ + struct clknode *clk; + struct jz4780_clk_otg_sc *sc; + + clk = clknode_create(clkdom, &jz4780_clk_otg_class, clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + sc->clk_mtx = dev_mtx; + sc->clk_res = mem_res; + clknode_register(clkdom, clk); + return (0); +} Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_clk_otg.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_clk_pll.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_clk_pll.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_clk_pll.c (revision 308868) @@ -0,0 +1,234 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + */ + +/* + * Ingenic JZ4780 CGU driver. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +/********************************************************************** + * JZ4780 PLL control register bit fields + **********************************************************************/ +#define CGU_PLL_M_SHIFT 19 +#define CGU_PLL_M_WIDTH 13 + +#define CGU_PLL_N_SHIFT 13 +#define CGU_PLL_N_WIDTH 6 + +#define CGU_PLL_OD_SHIFT 9 +#define CGU_PLL_OD_WIDTH 4 + +#define CGU_PLL_LOCK_SHIFT 6 +#define CGU_PLL_LOCK_WIDTH 1 + +#define CGU_PLL_ON_SHIFT 4 +#define CGU_PLL_ON_WIDTH 1 + +#define CGU_PLL_MODE_SHIFT 3 +#define CGU_PLL_MODE_WIDTH 1 + +#define CGU_PLL_BP_SHIFT 1 +#define CGU_PLL_BP_WIDTH 1 + +#define CGU_PLL_EN_SHIFT 0 +#define CGU_PLL_EN_WIDTH 1 + +/* JZ4780 PLL clock */ +static int jz4780_clk_pll_init(struct clknode *clk, device_t dev); +static int jz4780_clk_pll_recalc_freq(struct clknode *clk, uint64_t *freq); +static int jz4780_clk_pll_set_freq(struct clknode *clk, uint64_t fin, + uint64_t *fout, int flags, int *stop); + +struct jz4780_clk_pll_sc { + struct mtx *clk_mtx; + struct resource *clk_res; + uint32_t clk_reg; +}; + +/* + * JZ4780 PLL clock methods + */ +static clknode_method_t jz4780_clk_pll_methods[] = { + CLKNODEMETHOD(clknode_init, jz4780_clk_pll_init), + CLKNODEMETHOD(clknode_recalc_freq, jz4780_clk_pll_recalc_freq), + CLKNODEMETHOD(clknode_set_freq, jz4780_clk_pll_set_freq), + + CLKNODEMETHOD_END +}; +DEFINE_CLASS_1(jz4780_clk_pll, jz4780_clk_pll_class, jz4780_clk_pll_methods, + sizeof(struct jz4780_clk_pll_sc), clknode_class); + +static int +jz4780_clk_pll_init(struct clknode *clk, device_t dev) +{ + struct jz4780_clk_pll_sc *sc; + uint32_t reg; + + sc = clknode_get_softc(clk); + CLK_LOCK(sc); + reg = CLK_RD_4(sc, sc->clk_reg); + CLK_WR_4(sc, sc->clk_reg, reg); + CLK_UNLOCK(sc); + + clknode_init_parent_idx(clk, 0); + return (0); +} + +static int +jz4780_clk_pll_recalc_freq(struct clknode *clk, uint64_t *freq) +{ + struct jz4780_clk_pll_sc *sc; + uint32_t reg, m, n, od; + + sc = clknode_get_softc(clk); + reg = CLK_RD_4(sc, sc->clk_reg); + + /* Check for PLL enabled status */ + if (REG_GET(reg, CGU_PLL_EN) == 0) { + *freq = 0; + return 0; + } + + /* Return parent frequency if PPL is being bypassed */ + if (REG_GET(reg, CGU_PLL_BP) != 0) + return 0; + + m = REG_GET(reg, CGU_PLL_M) + 1; + n = REG_GET(reg, CGU_PLL_N) + 1; + od = REG_GET(reg, CGU_PLL_OD) + 1; + + /* Sanity check values */ + if (m == 0 || n == 0 || od == 0) { + *freq = 0; + return (EINVAL); + } + + *freq = ((*freq / n) * m) / od; + return (0); +} + +#define MHZ (1000 * 1000) +#define PLL_TIMEOUT 100 + +static int +jz4780_clk_pll_wait_lock(struct jz4780_clk_pll_sc *sc) +{ + int i; + + for (i = 0; i < PLL_TIMEOUT; i++) { + if (CLK_RD_4(sc, sc->clk_reg) & REG_VAL(CGU_PLL_LOCK, 1)) + return (0); + DELAY(1000); + } + return (ETIMEDOUT); +} + +static int +jz4780_clk_pll_set_freq(struct clknode *clk, uint64_t fin, + uint64_t *fout, int flags, int *stop) +{ + struct jz4780_clk_pll_sc *sc; + uint32_t reg, m, n, od; + int rv; + + sc = clknode_get_softc(clk); + + /* Should be able to figure all clocks with m & n only */ + od = 1; + + m = MIN((uint32_t)(*fout / MHZ), (1u << CGU_PLL_M_WIDTH)); + m = MIN(m, 1); + + n = MIN((uint32_t)(fin / MHZ), (1u << CGU_PLL_N_WIDTH)); + n = MIN(n, 1); + + if (flags & CLK_SET_DRYRUN) { + if (((flags & (CLK_SET_ROUND_UP | CLK_SET_ROUND_DOWN)) == 0) && + (*fout != (((fin / n) * m) / od))) + return (ERANGE); + + *fout = ((fin / n) * m) / od; + return (0); + } + + CLK_LOCK(sc); + reg = CLK_RD_4(sc, sc->clk_reg); + + /* Set the calculated values */ + reg = REG_SET(reg, CGU_PLL_M, m - 1); + reg = REG_SET(reg, CGU_PLL_N, n - 1); + reg = REG_SET(reg, CGU_PLL_OD, od - 1); + + /* Enable the PLL */ + reg = REG_SET(reg, CGU_PLL_EN, 1); + reg = REG_SET(reg, CGU_PLL_BP, 0); + + /* Initiate the change */ + CLK_WR_4(sc, sc->clk_reg, reg); + + /* Wait for PLL to lock */ + rv = jz4780_clk_pll_wait_lock(sc); + CLK_UNLOCK(sc); + if (rv != 0) + return (rv); + + *fout = ((fin / n) * m) / od; + return (0); +} + +int jz4780_clk_pll_register(struct clkdom *clkdom, + struct clknode_init_def *clkdef, struct mtx *dev_mtx, + struct resource *mem_res, uint32_t mem_reg) +{ + struct clknode *clk; + struct jz4780_clk_pll_sc *sc; + + clk = clknode_create(clkdom, &jz4780_clk_pll_class, clkdef); + if (clk == NULL) + return (1); + + sc = clknode_get_softc(clk); + sc->clk_mtx = dev_mtx; + sc->clk_res = mem_res; + sc->clk_reg = mem_reg; + clknode_register(clkdom, clk); + return (0); +} Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_clk_pll.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_clock.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_clock.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_clock.c (revision 308868) @@ -0,0 +1,831 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + */ + +/* + * Ingenic JZ4780 CGU driver. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +#include +#include +#include + +#include "clkdev_if.h" + +#include + +/********************************************************************** + * JZ4780 CGU clock domain + **********************************************************************/ +struct jz4780_clock_softc { + device_t dev; + struct resource *res[1]; + struct mtx mtx; + struct clkdom *clkdom; +}; + +static struct resource_spec jz4780_clock_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +struct jz4780_clk_pll_def { + uint16_t clk_id; + uint16_t clk_reg; + const char *clk_name; + const char *clk_pname[1]; +}; + +#define PLL(_id, cname, pname, reg) { \ + .clk_id = _id, \ + .clk_reg = reg, \ + .clk_name = cname, \ + .clk_pname[0] = pname, \ +} + +struct jz4780_clk_gate_def { + uint16_t clk_id; + uint16_t clk_bit; + const char *clk_name; + const char *clk_pname[1]; +}; + +#define GATE(_id, cname, pname, bit) { \ + .clk_id = _id, \ + .clk_bit = bit, \ + .clk_name = cname, \ + .clk_pname[0] = pname, \ +} + +#define MUX(reg, shift, bits, map) \ + .clk_mux.mux_reg = (reg), \ + .clk_mux.mux_shift = (shift), \ + .clk_mux.mux_bits = (bits), \ + .clk_mux.mux_map = (map), +#define NO_MUX + +#define DIV(reg, shift, lg, bits, ce, st, bb) \ + .clk_div.div_reg = (reg), \ + .clk_div.div_shift = (shift), \ + .clk_div.div_bits = (bits), \ + .clk_div.div_lg = (lg), \ + .clk_div.div_ce_bit = (ce), \ + .clk_div.div_st_bit = (st), \ + .clk_div.div_busy_bit = (bb), +#define NO_DIV \ + +#define GATEBIT(bit) \ + .clk_gate_bit = (bit), +#define NO_GATE \ + .clk_gate_bit = (-1), + +#define PLIST(pnames...) \ + .clk_pnames = { pnames }, + +#define GENCLK(id, name, type, parents, mux, div, gt) { \ + .clk_id = id, \ + .clk_type = type, \ + .clk_name = name, \ + parents \ + mux \ + div \ + gt \ +} + +/* PLL definitions */ +static struct jz4780_clk_pll_def pll_clks[] = { + PLL(JZ4780_CLK_APLL, "apll", "ext", JZ_CPAPCR), + PLL(JZ4780_CLK_MPLL, "mpll", "ext", JZ_CPMPCR), + PLL(JZ4780_CLK_EPLL, "epll", "ext", JZ_CPEPCR), + PLL(JZ4780_CLK_VPLL, "vpll", "ext", JZ_CPVPCR), +}; + +/* OTG PHY clock (reuse gate def structure */ +static struct jz4780_clk_gate_def otg_clks[] = { + GATE(JZ4780_CLK_OTGPHY, "otg_phy", "ext", 0), +}; + +static const struct jz4780_clk_descr gen_clks[] = { + GENCLK(JZ4780_CLK_SCLKA, "sclk_a", CLK_MASK_MUX, + PLIST("apll", "ext", "rtc"), + MUX(JZ_CPCCR, 30, 2, 0x7), + NO_DIV, + NO_GATE + ), + + GENCLK(JZ4780_CLK_CPUMUX, "cpumux", CLK_MASK_MUX, + PLIST("sclk_a", "mpll", "epll"), + MUX(JZ_CPCCR, 28, 2, 0x7), + NO_DIV, + NO_GATE + ), + + GENCLK(JZ4780_CLK_CPU, "cpu", CLK_MASK_DIV, + PLIST("cpumux"), + NO_MUX, + DIV(JZ_CPCCR, 0, 0, 4, 22, -1, -1), + NO_GATE + ), + + GENCLK(JZ4780_CLK_L2CACHE, "l2cache", CLK_MASK_DIV, + PLIST("cpumux"), + NO_MUX, + DIV(JZ_CPCCR, 4, 0, 4, -1, -1, -1), + NO_GATE + ), + + GENCLK(JZ4780_CLK_AHB0, "ahb0", CLK_MASK_MUX | CLK_MASK_DIV, + PLIST("sclk_a", "mpll", "epll"), + MUX(JZ_CPCCR, 26, 2, 0x7), + DIV(JZ_CPCCR, 8, 0, 4, 21, -1, -1), + NO_GATE + ), + + GENCLK(JZ4780_CLK_AHB2PMUX, "ahb2_apb_mux", CLK_MASK_MUX, + PLIST("sclk_a", "mpll", "rtc"), + MUX(JZ_CPCCR, 24, 2, 0x7), + NO_DIV, + NO_GATE + ), + + GENCLK(JZ4780_CLK_AHB2, "ahb2", CLK_MASK_DIV, + PLIST("ahb2_apb_mux"), + NO_MUX, + DIV(JZ_CPCCR, 12, 0, 4, 20, -1, -1), + NO_GATE + ), + + GENCLK(JZ4780_CLK_PCLK, "pclk", CLK_MASK_DIV, + PLIST("ahb2_apb_mux"), + NO_MUX, + DIV(JZ_CPCCR, 16, 0, 4, 20, -1, -1), + NO_GATE + ), + + GENCLK(JZ4780_CLK_DDR, "ddr", CLK_MASK_MUX | CLK_MASK_DIV, + PLIST("sclk_a", "mpll"), + MUX(JZ_DDCDR, 30, 2, 0x6), + DIV(JZ_DDCDR, 0, 0, 4, 29, 28, 27), + NO_GATE + ), + + GENCLK(JZ4780_CLK_VPU, "vpu", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE, + PLIST("sclk_a", "mpll", "epll"), + MUX(JZ_VPUCDR, 30, 2, 0xe), + DIV(JZ_VPUCDR, 0, 0, 4, 29, 28, 27), + GATEBIT(32 + 2) + ), + + GENCLK(JZ4780_CLK_I2SPLL, "i2s_pll", CLK_MASK_MUX | CLK_MASK_DIV, + PLIST("sclk_a", "epll"), + MUX(JZ_I2SCDR, 30, 1, 0xc), + DIV(JZ_I2SCDR, 0, 0, 8, 29, 28, 27), + NO_GATE + ), + + GENCLK(JZ4780_CLK_I2S, "i2s", CLK_MASK_MUX, + PLIST("ext", "i2s_pll"), + MUX(JZ_I2SCDR, 31, 1, 0xc), + NO_DIV, + NO_GATE + ), + + GENCLK(JZ4780_CLK_LCD0PIXCLK, "lcd0pixclk", CLK_MASK_MUX | CLK_MASK_DIV, + PLIST("sclk_a", "mpll", "vpll"), + MUX(JZ_LP0CDR, 30, 2, 0xe), + DIV(JZ_LP0CDR, 0, 0, 8, 28, 27, 26), + NO_GATE + ), + + GENCLK(JZ4780_CLK_LCD1PIXCLK, "lcd1pixclk", CLK_MASK_MUX | CLK_MASK_DIV, + PLIST("sclk_a", "mpll", "vpll"), + MUX(JZ_LP1CDR, 30, 2, 0xe), + DIV(JZ_LP1CDR, 0, 0, 8, 28, 27, 26), + NO_GATE + ), + + GENCLK(JZ4780_CLK_MSCMUX, "msc_mux", CLK_MASK_MUX, + PLIST("sclk_a", "mpll"), + MUX(JZ_MSC0CDR, 30, 2, 0x6), + NO_DIV, + NO_GATE + ), + + GENCLK(JZ4780_CLK_MSC0, "msc0", CLK_MASK_DIV | CLK_MASK_GATE, + PLIST("msc_mux"), + NO_MUX, + DIV(JZ_MSC0CDR, 0, 1, 8, 29, 28, 27), + GATEBIT(3) + ), + + GENCLK(JZ4780_CLK_MSC1, "msc1", CLK_MASK_DIV | CLK_MASK_GATE, + PLIST("msc_mux"), + NO_MUX, + DIV(JZ_MSC1CDR, 0, 1, 8, 29, 28, 27), + GATEBIT(11) + ), + + GENCLK(JZ4780_CLK_MSC2, "msc2", CLK_MASK_DIV | CLK_MASK_GATE, + PLIST("msc_mux"), + NO_MUX, + DIV(JZ_MSC2CDR, 0, 1, 8, 29, 28, 27), + GATEBIT(12) + ), + + GENCLK(JZ4780_CLK_UHC, "uhc", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE, + PLIST("sclk_a", "mpll", "epll", "otg_phy"), + MUX(JZ_UHCCDR, 30, 2, 0xf), + DIV(JZ_UHCCDR, 0, 0, 8, 29, 28, 27), + GATEBIT(24) + ), + + GENCLK(JZ4780_CLK_SSIPLL, "ssi_pll", CLK_MASK_MUX | CLK_MASK_DIV, + PLIST("sclk_a", "mpll"), + MUX(JZ_SSICDR, 30, 1, 0xc), + DIV(JZ_SSICDR, 0, 0, 8, 29, 28, 27), + NO_GATE + ), + + GENCLK(JZ4780_CLK_SSI, "ssi", CLK_MASK_MUX, + PLIST("ext", "ssi_pll"), + MUX(JZ_SSICDR, 31, 1, 0xc), + NO_DIV, + NO_GATE + ), + + GENCLK(JZ4780_CLK_CIMMCLK, "cim_mclk", CLK_MASK_MUX | CLK_MASK_DIV, + PLIST("sclk_a", "mpll"), + MUX(JZ_CIMCDR, 31, 1, 0xc), + DIV(JZ_CIMCDR, 0, 0, 8, 30, 29, 28), + NO_GATE + ), + + GENCLK(JZ4780_CLK_PCMPLL, "pcm_pll", CLK_MASK_MUX | CLK_MASK_DIV, + PLIST("sclk_a", "mpll", "epll", "vpll"), + MUX(JZ_PCMCDR, 29, 2, 0xf), + DIV(JZ_PCMCDR, 0, 0, 8, 28, 27, 26), + NO_GATE + ), + + GENCLK(JZ4780_CLK_PCM, "pcm", CLK_MASK_MUX | CLK_MASK_GATE, + PLIST("ext", "pcm_pll"), + MUX(JZ_PCMCDR, 31, 1, 0xc), + NO_DIV, + GATEBIT(32 + 3) + ), + + GENCLK(JZ4780_CLK_GPU, "gpu", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE, + PLIST("sclk_a", "mpll", "epll"), + MUX(JZ_GPUCDR, 30, 2, 0x7), + DIV(JZ_GPUCDR, 0, 0, 4, 29, 28, 27), + GATEBIT(32 + 4) + ), + + GENCLK(JZ4780_CLK_HDMI, "hdmi", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE, + PLIST("sclk_a", "mpll", "vpll"), + MUX(JZ_HDMICDR, 30, 2, 0xe), + DIV(JZ_HDMICDR, 0, 0, 8, 29, 28, 26), + GATEBIT(32 + 9) + ), + + GENCLK(JZ4780_CLK_BCH, "bch", CLK_MASK_MUX | CLK_MASK_DIV | CLK_MASK_GATE, + PLIST("sclk_a", "mpll", "epll"), + MUX(JZ_BCHCDR, 30, 2, 0x7), + DIV(JZ_BCHCDR, 0, 0, 4, 29, 28, 27), + GATEBIT(1) + ), +}; + +static struct jz4780_clk_gate_def gate_clks[] = { + GATE(JZ4780_CLK_NEMC, "nemc", "ahb2", 0), + GATE(JZ4780_CLK_OTG0, "otg0", "ext", 2), + GATE(JZ4780_CLK_SSI0, "ssi0", "ssi", 4), + GATE(JZ4780_CLK_SMB0, "smb0", "pclk", 5), + GATE(JZ4780_CLK_SMB1, "smb1", "pclk", 6), + GATE(JZ4780_CLK_SCC, "scc", "ext", 7), + GATE(JZ4780_CLK_AIC, "aic", "ext", 8), + GATE(JZ4780_CLK_TSSI0, "tssi0", "ext", 9), + GATE(JZ4780_CLK_OWI, "owi", "ext", 10), + GATE(JZ4780_CLK_KBC, "kbc", "ext", 13), + GATE(JZ4780_CLK_SADC, "sadc", "ext", 14), + GATE(JZ4780_CLK_UART0, "uart0", "ext", 15), + GATE(JZ4780_CLK_UART1, "uart1", "ext", 16), + GATE(JZ4780_CLK_UART2, "uart2", "ext", 17), + GATE(JZ4780_CLK_UART3, "uart3", "ext", 18), + GATE(JZ4780_CLK_SSI1, "ssi1", "ssi", 19), + GATE(JZ4780_CLK_SSI2, "ssi2", "ssi", 20), + GATE(JZ4780_CLK_PDMA, "pdma", "ext", 21), + GATE(JZ4780_CLK_GPS, "gps", "ext", 22), + GATE(JZ4780_CLK_MAC, "mac", "ext", 23), + GATE(JZ4780_CLK_SMB2, "smb2", "pclk", 25), + GATE(JZ4780_CLK_CIM, "cim", "ext", 26), + GATE(JZ4780_CLK_LCD, "lcd", "ext", 28), + GATE(JZ4780_CLK_TVE, "tve", "lcd", 27), + GATE(JZ4780_CLK_IPU, "ipu", "ext", 29), + GATE(JZ4780_CLK_DDR0, "ddr0", "ddr", 30), + GATE(JZ4780_CLK_DDR1, "ddr1", "ddr", 31), + GATE(JZ4780_CLK_SMB3, "smb3", "pclk", 32 + 0), + GATE(JZ4780_CLK_TSSI1, "tssi1", "ext", 32 + 1), + GATE(JZ4780_CLK_COMPRESS, "compress", "ext", 32 + 5), + GATE(JZ4780_CLK_AIC1, "aic1", "ext", 32 + 6), + GATE(JZ4780_CLK_GPVLC, "gpvlc", "ext", 32 + 7), + GATE(JZ4780_CLK_OTG1, "otg1", "ext", 32 + 8), + GATE(JZ4780_CLK_UART4, "uart4", "ext", 32 + 10), + GATE(JZ4780_CLK_AHBMON, "ahb_mon", "ext", 32 + 11), + GATE(JZ4780_CLK_SMB4, "smb4", "pclk", 32 + 12), + GATE(JZ4780_CLK_DES, "des", "ext", 32 + 13), + GATE(JZ4780_CLK_X2D, "x2d", "ext", 32 + 14), + GATE(JZ4780_CLK_CORE1, "core1", "cpu", 32 + 15), +}; + +static int +jz4780_clock_register(struct jz4780_clock_softc *sc) +{ + int i, ret; + + /* Register PLLs */ + for (i = 0; i < nitems(pll_clks); i++) { + struct clknode_init_def clkdef; + + clkdef.id = pll_clks[i].clk_id; + clkdef.name = __DECONST(char *, pll_clks[i].clk_name); + clkdef.parent_names = pll_clks[i].clk_pname; + clkdef.parent_cnt = 1; + clkdef.flags = CLK_NODE_STATIC_STRINGS; + + ret = jz4780_clk_pll_register(sc->clkdom, &clkdef, &sc->mtx, + sc->res[0], pll_clks[i].clk_reg); + if (ret != 0) + return (ret); + } + + /* Register OTG clock */ + for (i = 0; i < nitems(otg_clks); i++) { + struct clknode_init_def clkdef; + + clkdef.id = otg_clks[i].clk_id; + clkdef.name = __DECONST(char *, otg_clks[i].clk_name); + clkdef.parent_names = otg_clks[i].clk_pname; + clkdef.parent_cnt = 1; + clkdef.flags = CLK_NODE_STATIC_STRINGS; + + ret = jz4780_clk_otg_register(sc->clkdom, &clkdef, &sc->mtx, + sc->res[0]); + if (ret != 0) + return (ret); + } + + /* Register muxes and divisors */ + for (i = 0; i < nitems(gen_clks); i++) { + ret = jz4780_clk_gen_register(sc->clkdom, &gen_clks[i], + &sc->mtx, sc->res[0]); + if (ret != 0) + return (ret); + } + + /* Register simple gates */ + for (i = 0; i < nitems(gate_clks); i++) { + struct clk_gate_def gatedef; + + gatedef.clkdef.id = gate_clks[i].clk_id; + gatedef.clkdef.name = __DECONST(char *, gate_clks[i].clk_name); + gatedef.clkdef.parent_names = gate_clks[i].clk_pname; + gatedef.clkdef.parent_cnt = 1; + gatedef.clkdef.flags = CLK_NODE_STATIC_STRINGS; + + if (gate_clks[i].clk_bit < 32) { + gatedef.offset = JZ_CLKGR0; + gatedef.shift = gate_clks[i].clk_bit; + } else { + gatedef.offset = JZ_CLKGR1; + gatedef.shift = gate_clks[i].clk_bit - 32; + } + gatedef.mask = 1; + gatedef.on_value = 0; + gatedef.off_value = 1; + gatedef.gate_flags = 0; + + ret = clknode_gate_register(sc->clkdom, &gatedef); + if (ret != 0) + return (ret); + + } + + return (0); +} + +static int +jz4780_clock_fixup(struct jz4780_clock_softc *sc) +{ + struct clknode *clk_uhc; + int ret; + + /* + * Make UHC mux use MPLL as the source. It defaults to OTG_PHY + * and that somehow just does not work. + */ + clkdom_xlock(sc->clkdom); + + /* Assume the worst */ + ret = ENXIO; + + clk_uhc = clknode_find_by_id(sc->clkdom, JZ4780_CLK_UHC); + if (clk_uhc != NULL) { + ret = clknode_set_parent_by_name(clk_uhc, "mpll"); + if (ret != 0) + device_printf(sc->dev, + "unable to reparent uhc clock\n"); + else + ret = clknode_set_freq(clk_uhc, 48000000, 0, 0); + if (ret != 0) + device_printf(sc->dev, "unable to init uhc clock\n"); + } else + device_printf(sc->dev, "unable to lookup uhc clock\n"); + + clkdom_unlock(sc->clkdom); + return (ret); +} + +#define CGU_LOCK(sc) mtx_lock(&(sc)->mtx) +#define CGU_UNLOCK(sc) mtx_unlock(&(sc)->mtx) +#define CGU_LOCK_INIT(sc) \ + mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \ + "jz4780-cgu", MTX_DEF) +#define CGU_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx); + +#define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val)) +#define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], (reg)) + +static int +jz4780_clock_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-cgu")) + return (ENXIO); + + device_set_desc(dev, "Ingenic jz4780 CGU"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jz4780_clock_attach(device_t dev) +{ + struct jz4780_clock_softc *sc; + + sc = device_get_softc(dev); + if (bus_alloc_resources(dev, jz4780_clock_spec, sc->res)) { + device_printf(dev, "could not allocate resources for device\n"); + return (ENXIO); + } + + sc->dev = dev; + CGU_LOCK_INIT(sc); + + sc->clkdom = clkdom_create(dev); + if (sc->clkdom == NULL) + goto fail; + if (jz4780_clock_register(sc) != 0) + goto fail; + if (clkdom_finit(sc->clkdom) != 0) + goto fail; + if (jz4780_clock_fixup(sc) != 0) + goto fail; + if (bootverbose) + clkdom_dump(sc->clkdom); + + return (0); +fail: + bus_release_resources(dev, jz4780_clock_spec, sc->res); + CGU_LOCK_DESTROY(sc); + + return (ENXIO); +} + +static int +jz4780_clock_detach(device_t dev) +{ + struct jz4780_clock_softc *sc; + + sc = device_get_softc(dev); + bus_release_resources(dev, jz4780_clock_spec, sc->res); + CGU_LOCK_DESTROY(sc); + + return (0); +} + +static int +jz4780_clock_write_4(device_t dev, bus_addr_t addr, uint32_t val) +{ + struct jz4780_clock_softc *sc; + + sc = device_get_softc(dev); + CSR_WRITE_4(sc, addr, val); + return (0); +} + +static int +jz4780_clock_read_4(device_t dev, bus_addr_t addr, uint32_t *val) +{ + struct jz4780_clock_softc *sc; + + sc = device_get_softc(dev); + *val = CSR_READ_4(sc, addr); + return (0); +} + +static int +jz4780_clock_modify_4(device_t dev, bus_addr_t addr, uint32_t clear_mask, + uint32_t set_mask) +{ + struct jz4780_clock_softc *sc; + uint32_t val; + + sc = device_get_softc(dev); + val = CSR_READ_4(sc, addr); + val &= clear_mask; + val |= set_mask; + CSR_WRITE_4(sc, addr, val); + return (0); +} + +static void +jz4780_clock_device_lock(device_t dev) +{ + struct jz4780_clock_softc *sc; + + sc = device_get_softc(dev); + CGU_LOCK(sc); +} + +static void +jz4780_clock_device_unlock(device_t dev) +{ + struct jz4780_clock_softc *sc; + + sc = device_get_softc(dev); + CGU_UNLOCK(sc); +} + +static device_method_t jz4780_clock_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_clock_probe), + DEVMETHOD(device_attach, jz4780_clock_attach), + DEVMETHOD(device_detach, jz4780_clock_detach), + + /* Clock device interface */ + DEVMETHOD(clkdev_write_4, jz4780_clock_write_4), + DEVMETHOD(clkdev_read_4, jz4780_clock_read_4), + DEVMETHOD(clkdev_modify_4, jz4780_clock_modify_4), + DEVMETHOD(clkdev_device_lock, jz4780_clock_device_lock), + DEVMETHOD(clkdev_device_unlock, jz4780_clock_device_unlock), + + DEVMETHOD_END +}; + +static driver_t jz4780_clock_driver = { + "cgu", + jz4780_clock_methods, + sizeof(struct jz4780_clock_softc), +}; + +static devclass_t jz4780_clock_devclass; + +EARLY_DRIVER_MODULE(jz4780_clock, simplebus, jz4780_clock_driver, + jz4780_clock_devclass, 0, 0, BUS_PASS_CPU + BUS_PASS_ORDER_LATE); + +static int +jz4780_ehci_clk_config(struct jz4780_clock_softc *sc) +{ + clk_t phy_clk, ext_clk; + uint64_t phy_freq; + int err; + + phy_clk = NULL; + ext_clk = NULL; + err = -1; + + /* Set phy timing by copying it from ext */ + if (clk_get_by_id(sc->dev, sc->clkdom, JZ4780_CLK_OTGPHY, + &phy_clk) != 0) + goto done; + if (clk_get_parent(phy_clk, &ext_clk) != 0) + goto done; + if (clk_get_freq(ext_clk, &phy_freq) != 0) + goto done; + if (clk_set_freq(phy_clk, phy_freq, 0) != 0) + goto done; + err = 0; +done: + clk_release(ext_clk); + clk_release(phy_clk); + + return (err); +} + +int +jz4780_ohci_enable(void) +{ + device_t dev; + struct jz4780_clock_softc *sc; + uint32_t reg; + + dev = devclass_get_device(jz4780_clock_devclass, 0); + if (dev == NULL) + return (-1); + + sc = device_get_softc(dev); + CGU_LOCK(sc); + + /* Do not force port1 to suspend mode */ + reg = CSR_READ_4(sc, JZ_OPCR); + reg |= OPCR_SPENDN1; + CSR_WRITE_4(sc, JZ_OPCR, reg); + + CGU_UNLOCK(sc); + return (0); +} + +int +jz4780_ehci_enable(void) +{ + device_t dev; + struct jz4780_clock_softc *sc; + uint32_t reg; + + dev = devclass_get_device(jz4780_clock_devclass, 0); + if (dev == NULL) + return (-1); + + sc = device_get_softc(dev); + + /* + * EHCI should use MPPL as a parent, but Linux configures OTG + * clock anyway. Follow their lead blindly. + */ + if (jz4780_ehci_clk_config(sc) != 0) + return (-1); + + CGU_LOCK(sc); + + /* Enable OTG, should not be necessary since we use PLL clock */ + reg = CSR_READ_4(sc, JZ_USBPCR); + reg &= ~(PCR_OTG_DISABLE); + CSR_WRITE_4(sc, JZ_USBPCR, reg); + + /* Do not force port1 to suspend mode */ + reg = CSR_READ_4(sc, JZ_OPCR); + reg |= OPCR_SPENDN1; + CSR_WRITE_4(sc, JZ_OPCR, reg); + + /* D- pulldown */ + reg = CSR_READ_4(sc, JZ_USBPCR1); + reg |= PCR_DMPD1; + CSR_WRITE_4(sc, JZ_USBPCR1, reg); + + /* D+ pulldown */ + reg = CSR_READ_4(sc, JZ_USBPCR1); + reg |= PCR_DPPD1; + CSR_WRITE_4(sc, JZ_USBPCR1, reg); + + /* 16 bit bus witdth for port 1*/ + reg = CSR_READ_4(sc, JZ_USBPCR1); + reg |= PCR_WORD_I_F1 | PCR_WORD_I_F0; + CSR_WRITE_4(sc, JZ_USBPCR1, reg); + + /* Reset USB */ + reg = CSR_READ_4(sc, JZ_USBPCR); + reg |= PCR_POR; + CSR_WRITE_4(sc, JZ_USBPCR, reg); + DELAY(1); + reg = CSR_READ_4(sc, JZ_USBPCR); + reg &= ~(PCR_POR); + CSR_WRITE_4(sc, JZ_USBPCR, reg); + + /* Soft-reset USB */ + reg = CSR_READ_4(sc, JZ_SRBC); + reg |= SRBC_UHC_SR; + CSR_WRITE_4(sc, JZ_SRBC, reg); + /* 300ms */ + DELAY(300*hz/1000); + + reg = CSR_READ_4(sc, JZ_SRBC); + reg &= ~(SRBC_UHC_SR); + CSR_WRITE_4(sc, JZ_SRBC, reg); + + /* 300ms */ + DELAY(300*hz/1000); + + CGU_UNLOCK(sc); + return (0); +} + +#define USBRESET_DETECT_TIME 0x96 + +int +jz4780_otg_enable(void) +{ + device_t dev; + struct jz4780_clock_softc *sc; + uint32_t reg; + + dev = devclass_get_device(jz4780_clock_devclass, 0); + if (dev == NULL) + return (-1); + + sc = device_get_softc(dev); + + CGU_LOCK(sc); + + /* Select Synopsys OTG mode */ + reg = CSR_READ_4(sc, JZ_USBPCR1); + reg |= PCR_SYNOPSYS; + + /* Set UTMI bus width to 16 bit */ + reg |= PCR_WORD_I_F0 | PCR_WORD_I_F1; + CSR_WRITE_4(sc, JZ_USBPCR1, reg); + + /* Blah */ + reg = CSR_READ_4(sc, JZ_USBVBFIL); + reg = REG_SET(reg, USBVBFIL_IDDIGFIL, 0); + reg = REG_SET(reg, USBVBFIL_USBVBFIL, 0); + CSR_WRITE_4(sc, JZ_USBVBFIL, reg); + + /* Setup reset detect time */ + reg = CSR_READ_4(sc, JZ_USBRDT); + reg = REG_SET(reg, USBRDT_USBRDT, USBRESET_DETECT_TIME); + reg |= USBRDT_VBFIL_LD_EN; + CSR_WRITE_4(sc, JZ_USBRDT, reg); + + /* Setup USBPCR bits */ + reg = CSR_READ_4(sc, JZ_USBPCR); + reg |= PCR_USB_MODE; + reg |= PCR_COMMONONN; + reg |= PCR_VBUSVLDEXT; + reg |= PCR_VBUSVLDEXTSEL; + reg &= ~(PCR_OTG_DISABLE); + CSR_WRITE_4(sc, JZ_USBPCR, reg); + + /* Reset USB */ + reg = CSR_READ_4(sc, JZ_USBPCR); + reg |= PCR_POR; + CSR_WRITE_4(sc, JZ_USBPCR, reg); + DELAY(1000); + reg = CSR_READ_4(sc, JZ_USBPCR); + reg &= ~(PCR_POR); + CSR_WRITE_4(sc, JZ_USBPCR, reg); + + /* Unsuspend OTG port */ + reg = CSR_READ_4(sc, JZ_OPCR); + reg |= OPCR_SPENDN0; + CSR_WRITE_4(sc, JZ_OPCR, reg); + + CGU_UNLOCK(sc); + return (0); +} Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_clock.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_clock.h =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_clock.h (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_clock.h (revision 308868) @@ -0,0 +1,36 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + * + * $FreeBSD$ + */ + +#ifndef JZ4780_CLOCK_H +#define JZ4780_CLOCK_H + +extern int jz4780_ehci_enable(void); +extern int jz4780_ohci_enable(void); +extern int jz4780_otg_enable(void); + +#endif Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_clock.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_cpuregs.h =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_cpuregs.h (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_cpuregs.h (revision 308868) @@ -0,0 +1,73 @@ +/*- + * Copyright (c) 2015 Alexander Kabaev + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * $FreeBSD$ + */ + +#ifndef JZ4780_CPUREGS_H +#define JZ4780_CPUREGS_H + +/* Core control register */ +#define JZ_CORECTL_SLP1M_SHIFT 17 +#define JZ_CORECTL_SLP1M (1u << JZ_CORECTL_SLP1M_SHIFT) +#define JZ_CORECTL_SLP0M_SHIFT 16 +#define JZ_CORECTL_SLP0M (1u << JZ_CORECTL_SLP0M_SHIFT) +#define JZ_CORECTL_RPC1_SHIFT 9 +#define JZ_CORECTL_RPC1 (1u << JZ_CORECTL_RPC1_SHIFT) +#define JZ_CORECTL_RPC0_SHIFT 8 +#define JZ_CORECTL_RPC0 (1u << JZ_CORECTL_RPC0_SHIFT) +#define JZ_CORECTL_SWRST1_SHIFT 1 +#define JZ_CORECTL_SWRST1 (1u << JZ_CORECTL_SWRST1_SHIFT) +#define JZ_CORECTL_SWRST0_SHIFT 0 +#define JZ_CORECTL_SWRST0 (1u << JZ_CORECTL_SWRST0_SHIFT) + +/* Core status register */ +#define JZ_CORESTS_SLP1_SHIFT 17 +#define JZ_CORESTS_SLP1 (1u << JZ_CORESTS_SLP1_SHIFT) +#define JZ_CORESTS_SLP0_SHIFT 16 +#define JZ_CORESTS_SLP0 (1u << JZ_CORESTS_SLP0_SHIFT) +#define JZ_CORESTS_IRQ1P_SHIFT 9 +#define JZ_CORESTS_IRQ1P (1u << JZ_CORESTS_IRQ1P_SHIFT) +#define JZ_CORESTS_IRQ0P_SHIFT 8 +#define JZ_CORESTS_IRQ0P (1u << JZ_CORESTS_IRQ0P_SHIFT) +#define JZ_CORESTS_MIRQ1P_SHIFT 1 +#define JZ_CORESTS_MIRQ1P (1u << JZ_CORESTS_MIRQ1P_SHIFT) +#define JZ_CORESTS_MIRQ0P_SHIFT 0 +#define JZ_CORESTS_MIRQ0P (1u << JZ_CORESTS_MIRQ0P_SHIFT) + +/* Reset entry and IRQ mask */ +#define JZ_REIM_ENTRY_SHIFT 16 +#define JZ_REIM_ENTRY_WIDTH 16 +#define JZ_REIM_ENTRY_MASK (0xFFFFu << JZ_REIM_ENTRY_SHIFT) +#define JZ_REIM_IRQ1M_SHIFT 9 +#define JZ_REIM_IRQ1M (1u << JZ_REIM_IRQ1M_SHIFT) +#define JZ_REIM_IRQ0M_SHIFT 8 +#define JZ_REIM_IRQ0M (1u << JZ_REIM_IRQ0M_SHIFT) +#define JZ_REIM_MIRQ1M_SHIFT 1 +#define JZ_REIM_MIRQ1M (1u << JZ_REIM_MIRQ1M_SHIFT) +#define JZ_REIM_MIRQ0M_SHIFT 0 +#define JZ_REIM_MIRQ0M (1u << JZ_REIM_MIRQ0M_SHIFT) + +#endif /* JZ4780_CPUREGS_H */ Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_cpuregs.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_dme.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_dme.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_dme.c (revision 308868) @@ -0,0 +1,124 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + */ + +/* + * Ingenic JZ4780 NAND and External Memory Controller (NEMC) driver. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +struct jz4780_dme_softc { + device_t dev; + struct resource *res[2]; +}; + +static struct resource_spec jz4780_dme_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_MEMORY, 1, RF_ACTIVE }, + { -1, 0 } +}; + +static int jz4780_dme_probe(device_t dev); +static int jz4780_dme_attach(device_t dev); +static int jz4780_dme_detach(device_t dev); + +static int +jz4780_dme_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "davicom,dm9000")) + return (ENXIO); + + device_set_desc(dev, "Davicom DM9000C 10/100BaseTX"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jz4780_dme_attach(device_t dev) +{ + struct jz4780_dme_softc *sc = device_get_softc(dev); + + sc->dev = dev; + + if (bus_alloc_resources(dev, jz4780_dme_spec, sc->res)) { + device_printf(dev, "could not allocate resources for device\n"); + return (ENXIO); + } + + return (0); +} + +static int +jz4780_dme_detach(device_t dev) +{ + struct jz4780_dme_softc *sc = device_get_softc(dev); + + bus_release_resources(dev, jz4780_dme_spec, sc->res); + return (0); +} + +static device_method_t jz4780_dme_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_dme_probe), + DEVMETHOD(device_attach, jz4780_dme_attach), + DEVMETHOD(device_detach, jz4780_dme_detach), + + DEVMETHOD_END +}; + +static driver_t jz4780_dme_driver = { + "dme", + jz4780_dme_methods, + sizeof(struct jz4780_dme_softc), +}; + +static devclass_t jz4780_dme_devclass; + +DRIVER_MODULE(jz4780_dme, simplebus, jz4780_dme_driver, + jz4780_dme_devclass, 0, 0); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_dme.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_dwc_fdt.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_dwc_fdt.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_dwc_fdt.c (revision 308868) @@ -0,0 +1,202 @@ +/* + * Copyright 2015 Alexander Kabaev . + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +#include +#include + +static device_probe_t jz4780_dwc_otg_probe; +static device_attach_t jz4780_dwc_otg_attach; +static device_detach_t jz4780_dwc_otg_detach; + +struct jz4780_dwc_otg_softc { + struct dwc_otg_fdt_softc base; /* storage for DWC OTG code */ + clk_t phy_clk; + clk_t otg_clk; +}; + +static int +jz4780_dwc_otg_clk_enable(device_t dev) +{ + struct jz4780_dwc_otg_softc *sc; + int err; + + sc = device_get_softc(dev); + + /* Configure and enable phy clock */ + err = clk_get_by_ofw_name(dev, 0, "otg_phy", &sc->phy_clk); + if (err != 0) { + device_printf(dev, "unable to lookup %s clock\n", "otg_phy"); + return (err); + } + err = clk_set_freq(sc->phy_clk, 48000000, 0); + if (err != 0) { + device_printf(dev, "unable to set %s clock to 48 kHZ\n", + "otg_phy"); + return (err); + } + err = clk_enable(sc->phy_clk); + if (err != 0) { + device_printf(dev, "unable to enable %s clock\n", "otg_phy"); + return (err); + } + + /* Configure and enable otg1 clock */ + err = clk_get_by_ofw_name(dev, 0, "otg1", &sc->otg_clk); + if (err != 0) { + device_printf(dev, "unable to lookup %s clock\n", "otg1"); + return (err); + } + err = clk_enable(sc->phy_clk); + if (err != 0) { + device_printf(dev, "unable to enable %s clock\n", "otg1"); + return (err); + } + + return (0); +} + +static int +jz4780_dwc_otg_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-otg")) + return (ENXIO); + + device_set_desc(dev, "DWC OTG 2.0 integrated USB controller (jz4780)"); + + return (BUS_PROBE_VENDOR); +} + +static int +jz4780_dwc_otg_attach(device_t dev) +{ + struct jz4780_dwc_otg_softc *sc; + struct resource *res; + int err, rid; + + sc = device_get_softc(dev); + + err = jz4780_dwc_otg_clk_enable(dev); + if (err != 0) + goto fail; + + err = jz4780_otg_enable(); + if (err != 0) { + device_printf(dev, "CGU failed to enable OTG\n"); + goto fail; + } + + /* Voodoo: Switch off VBUS overcurrent detection in OTG PHY */ + res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (res != NULL) { + uint32_t reg; + + reg = bus_read_4(res, JZ_DWC2_GUSBCFG); + reg |= 0xc; + bus_write_4(res, JZ_DWC2_GUSBCFG, reg); + bus_release_resource(dev, SYS_RES_MEMORY, rid, res); + } + + sc->base.sc_otg.sc_phy_type = DWC_OTG_PHY_UTMI; + sc->base.sc_otg.sc_phy_bits = 16; + + err = dwc_otg_attach(dev); + if (err != 0) + goto fail; + + return (0); +fail: + if (sc->otg_clk) + clk_release(sc->otg_clk); + if (sc->phy_clk) + clk_release(sc->phy_clk); + return (err); +} + +static int +jz4780_dwc_otg_detach(device_t dev) +{ + struct jz4780_dwc_otg_softc *sc; + int err; + + err = dwc_otg_detach(dev); + if (err != 0) + return (err); + + sc = device_get_softc(dev); + if (sc->otg_clk) + clk_release(sc->otg_clk); + if (sc->phy_clk) + clk_release(sc->phy_clk); + return (0); +} + +static device_method_t jz4780_dwc_otg_methods[] = { + /* bus interface */ + DEVMETHOD(device_probe, jz4780_dwc_otg_probe), + DEVMETHOD(device_attach, jz4780_dwc_otg_attach), + DEVMETHOD(device_detach, jz4780_dwc_otg_detach), + + DEVMETHOD_END +}; + +static devclass_t jz4780_dwc_otg_devclass; + +DEFINE_CLASS_1(jzotg, jz4780_dwc_otg_driver, jz4780_dwc_otg_methods, + sizeof(struct jz4780_dwc_otg_softc), dwc_otg_driver); +DRIVER_MODULE(jzotg, simplebus, jz4780_dwc_otg_driver, + jz4780_dwc_otg_devclass, 0, 0); +MODULE_DEPEND(jzotg, usb, 1, 1, 1); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_dwc_fdt.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_efuse.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_efuse.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_efuse.c (revision 308868) @@ -0,0 +1,213 @@ +/*- + * Copyright (c) 2015 Alexander Kabaev + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include + +#include + +static struct ofw_compat_data compat_data[] = { + {"ingenic,jz4780-efuse", 1}, + {NULL, 0} +}; + +struct jz4780_efuse_data { + uint32_t serial_num; + uint32_t date; + uint8_t nanufacturer[2]; + uint8_t macaddr[6]; +} __packed; + +static struct resource_spec jz4780_efuse_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +struct jz4780_efuse_softc { + device_t dev; + struct resource *res[1]; + struct jz4780_efuse_data data; +}; + +#define CSR_WRITE_4(sc, reg, val) \ + bus_write_4((sc)->res[0], (reg), (val)) +#define CSR_READ_4(sc, reg) \ + bus_read_4((sc)->res[0], (reg)) + +#define JZ_EFUSE_BANK_SIZE (4096 / 8) /* Bank size is 4096 bits */ + +static int +jz4780_efuse_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (ofw_bus_search_compatible(dev, compat_data)->ocd_data == 0) + return (ENXIO); + + return (BUS_PROBE_DEFAULT); +} + +static void +jz4780_efuse_read_chunk(struct jz4780_efuse_softc *sc, int addr, uint8_t *buf, int len) +{ + uint32_t abuf; + int i, count; + + /* Setup to read proper bank */ + CSR_WRITE_4(sc, JZ_EFUCTRL, JZ_EFUSE_READ | + (addr < JZ_EFUSE_BANK_SIZE ? 0: JZ_EFUSE_BANK) | + (addr << JZ_EFUSE_ADDR_SHIFT) | + ((len - 1) << JZ_EFUSE_SIZE_SHIFT)); + /* Wait for read to complete */ + while ((CSR_READ_4(sc, JZ_EFUSTATE) & JZ_EFUSE_RD_DONE) == 0) + DELAY(1000); + + /* Round to 4 bytes for the simple loop below */ + count = len & ~3; + + for (i = 0; i < count; i += 4) { + abuf = CSR_READ_4(sc, JZ_EFUDATA0 + i); + memcpy(buf, &abuf, 4); + buf += 4; + } + + /* Read partial word and assign it byte-by-byte */ + if (i < len) { + abuf = CSR_READ_4(sc, JZ_EFUDATA0 + i); + for (/* none */; i < len; i++) { + buf[i] = abuf & 0xff; + abuf >>= 8; + } + } +} + +static void +jz4780_efuse_read(struct jz4780_efuse_softc *sc, int addr, void *buf, int len) +{ + int chunk; + + while (len > 0) { + chunk = (len > 32) ? 32 : len; + jz4780_efuse_read_chunk(sc, addr, buf, chunk); + len -= chunk; + buf = (void *)((uintptr_t)buf + chunk); + addr += chunk; + } +} + +static void +jz4780_efuse_update_kenv(struct jz4780_efuse_softc *sc) +{ + char macstr[sizeof("xx:xx:xx:xx:xx:xx")]; + + /* + * Update hint in kernel env only if none is available yet. + * It is quite possible one was set by command line already. + */ + if (kern_getenv("hint.dme.0.macaddr") == NULL) { + snprintf(macstr, sizeof(macstr), "%6D", + sc->data.macaddr, ":"); + kern_setenv("hint.dme.0.macaddr", macstr); + } +} + +static int +jz4780_efuse_attach(device_t dev) +{ + struct jz4780_efuse_softc *sc; + + sc = device_get_softc(dev); + sc->dev = dev; + + if (bus_alloc_resources(dev, jz4780_efuse_spec, sc->res)) { + device_printf(dev, "could not allocate resources for device\n"); + return (ENXIO); + } + + /* + * Default RD_STROBE to 4 h2clk cycles, should already be set to 4 by reset + * but configure it anyway. + */ + CSR_WRITE_4(sc, JZ_EFUCFG, 0x00040000); + + /* Read user-id segment */ + jz4780_efuse_read(sc, 0x18, &sc->data, sizeof(sc->data)); + + /* + * Set resource hints for the dme device to discover its + * MAC address, if not set already. + */ + jz4780_efuse_update_kenv(sc); + + /* Resource conflicts with NEMC, release early */ + bus_release_resources(dev, jz4780_efuse_spec, sc->res); + return (0); +} + +static int +jz4780_efuse_detach(device_t dev) +{ + + return (0); +} + +static device_method_t jz4780_efuse_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_efuse_probe), + DEVMETHOD(device_attach, jz4780_efuse_attach), + DEVMETHOD(device_detach, jz4780_efuse_detach), + + DEVMETHOD_END +}; + +static driver_t jz4780_efuse_driver = { + "efuse", + jz4780_efuse_methods, + sizeof(struct jz4780_efuse_softc), +}; + +static devclass_t jz4780_efuse_devclass; +EARLY_DRIVER_MODULE(jz4780_efuse, simplebus, jz4780_efuse_driver, + jz4780_efuse_devclass, 0, 0, BUS_PASS_TIMER); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_efuse.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_ehci.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_ehci.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_ehci.c (revision 308868) @@ -0,0 +1,345 @@ +/*- + * Copyright (c) 2015 Oleksandr Tymoshenko . + * 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 ``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 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. + */ + +/* + * JZ4780 attachment driver for the USB Enhanced Host Controller. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include "opt_bus.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +#define EHCI_HC_DEVSTR "Ingenic JZ4780 EHCI" + +struct jz4780_ehci_softc { + ehci_softc_t base; /* storage for EHCI code */ + clk_t clk; + struct gpiobus_pin *gpio_vbus; +}; + +static device_probe_t jz4780_ehci_probe; +static device_attach_t jz4780_ehci_attach; +static device_detach_t jz4780_ehci_detach; + +static int +jz4780_ehci_vbus_gpio_enable(device_t dev) +{ + struct gpiobus_pin *gpio_vbus; + struct jz4780_ehci_softc *sc; + int err; + + sc = device_get_softc(dev); + + err = ofw_gpiobus_parse_gpios(dev, "ingenic,vbus-gpio", &gpio_vbus); + /* + * The pin can ne already mapped by other device. Optimistically + * surge ahead. + */ + if (err <= 0) + return (0); + + sc->gpio_vbus = gpio_vbus; + if (err > 1) { + device_printf(dev, "too many vbus gpios\n"); + return (ENXIO); + } + + if (sc->gpio_vbus != NULL) { + err = GPIO_PIN_SETFLAGS(sc->gpio_vbus->dev, sc->gpio_vbus->pin, + GPIO_PIN_OUTPUT); + if (err != 0) { + device_printf(dev, "Cannot configure GPIO pin %d on %s\n", + sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev)); + return (err); + } + + err = GPIO_PIN_SET(sc->gpio_vbus->dev, sc->gpio_vbus->pin, 1); + if (err != 0) { + device_printf(dev, "Cannot configure GPIO pin %d on %s\n", + sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev)); + return (err); + } + } + return (0); +} + +static int +jz4780_ehci_clk_enable(device_t dev) +{ + struct jz4780_ehci_softc *sc; + int err; + + sc = device_get_softc(dev); + + err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk); + if (err != 0) { + device_printf(dev, "unable to lookup device clock\n"); + return (err); + } + err = clk_enable(sc->clk); + if (err != 0) { + device_printf(dev, "unable to enable device clock\n"); + return (err); + } + err = clk_set_freq(sc->clk, 48000000, 0); + if (err != 0) { + device_printf(dev, "unable to set device clock to 48 kHZ\n"); + return (err); + } + return (0); +} + +static void +jz4780_ehci_intr(void *arg) +{ + + ehci_interrupt(arg); +} + +static int +jz4780_ehci_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-ehci")) + return (ENXIO); + + device_set_desc(dev, EHCI_HC_DEVSTR); + + return (BUS_PROBE_DEFAULT); +} + +static int +jz4780_ehci_attach(device_t dev) +{ + struct jz4780_ehci_softc *isc; + ehci_softc_t *sc; + int err; + int rid; + uint32_t reg; + + isc = device_get_softc(dev); + sc = &isc->base; + + /* initialise some bus fields */ + sc->sc_bus.parent = dev; + sc->sc_bus.devices = sc->sc_devices; + sc->sc_bus.devices_max = EHCI_MAX_DEVICES; + sc->sc_bus.dma_bits = 32; + + /* get all DMA memory */ + if (usb_bus_mem_alloc_all(&sc->sc_bus, + USB_GET_DMA_TAG(dev), &ehci_iterate_hw_softc)) { + return (ENOMEM); + } + + sc->sc_bus.usbrev = USB_REV_2_0; + + err = jz4780_ehci_vbus_gpio_enable(dev); + if (err) + goto error; + + rid = 0; + sc->sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, RF_ACTIVE); + if (!sc->sc_io_res) { + device_printf(dev, "Could not map memory\n"); + goto error; + } + + /* + * Craft special resource for bus space ops that handle + * byte-alignment of non-word addresses. + */ + sc->sc_io_tag = rman_get_bustag(sc->sc_io_res); + sc->sc_io_hdl = rman_get_bushandle(sc->sc_io_res); + sc->sc_io_size = rman_get_size(sc->sc_io_res); + + err = jz4780_ehci_clk_enable(dev); + if (err) + goto error; + + if (jz4780_ehci_enable() != 0) { + device_printf(dev, "CGU failed to enable EHCI\n"); + err = ENXIO; + goto error; + } + + EWRITE4(sc, EHCI_USBINTR, 0); + + rid = 0; + sc->sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE | RF_SHAREABLE); + if (sc->sc_irq_res == NULL) { + device_printf(dev, "Could not allocate irq\n"); + goto error; + } + sc->sc_bus.bdev = device_add_child(dev, "usbus", -1); + if (!sc->sc_bus.bdev) { + device_printf(dev, "Could not add USB device\n"); + goto error; + } + device_set_ivars(sc->sc_bus.bdev, &sc->sc_bus); + device_set_desc(sc->sc_bus.bdev, EHCI_HC_DEVSTR); + + sprintf(sc->sc_vendor, "Ingenic"); + + err = bus_setup_intr(dev, sc->sc_irq_res, INTR_TYPE_BIO | INTR_MPSAFE, + NULL, jz4780_ehci_intr, sc, &sc->sc_intr_hdl); + if (err) { + device_printf(dev, "Could not setup irq, %d\n", err); + sc->sc_intr_hdl = NULL; + goto error; + } + + err = ehci_init(sc); + if (!err) { + /* Voodoo: set utmi data bus width on controller to 16 bit */ + reg = EREAD4(sc, JZ_EHCI_REG_UTMI_BUS); + reg |= UTMI_BUS_WIDTH; + EWRITE4(sc, JZ_EHCI_REG_UTMI_BUS, reg); + + err = device_probe_and_attach(sc->sc_bus.bdev); + } + if (err) { + device_printf(dev, "USB init failed err=%d\n", err); + goto error; + } + return (0); + +error: + jz4780_ehci_detach(dev); + return (ENXIO); +} + +static int +jz4780_ehci_detach(device_t dev) +{ + struct jz4780_ehci_softc *isc; + ehci_softc_t *sc; + device_t bdev; + int err; + + isc = device_get_softc(dev); + sc = &isc->base; + + if (sc->sc_bus.bdev) { + bdev = sc->sc_bus.bdev; + device_detach(bdev); + device_delete_child(dev, bdev); + } + /* during module unload there are lots of children leftover */ + device_delete_children(dev); + + if (sc->sc_irq_res && sc->sc_intr_hdl) { + /* + * only call ehci_detach() after ehci_init() + */ + ehci_detach(sc); + + err = bus_teardown_intr(dev, sc->sc_irq_res, sc->sc_intr_hdl); + + if (err) + /* XXX or should we panic? */ + device_printf(dev, "Could not tear down irq, %d\n", + err); + sc->sc_intr_hdl = NULL; + } + + if (sc->sc_irq_res) { + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_irq_res); + sc->sc_irq_res = NULL; + } + if (sc->sc_io_res) { + bus_release_resource(dev, SYS_RES_MEMORY, 0, + sc->sc_io_res); + sc->sc_io_res = NULL; + } + + if (isc->clk) + clk_release(isc->clk); + + usb_bus_mem_free_all(&sc->sc_bus, &ehci_iterate_hw_softc); + free(isc->gpio_vbus, M_DEVBUF); + return (0); +} + +static device_method_t ehci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_ehci_probe), + DEVMETHOD(device_attach, jz4780_ehci_attach), + DEVMETHOD(device_detach, jz4780_ehci_detach), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + DEVMETHOD_END +}; + +static driver_t ehci_driver = { + .name = "ehci", + .methods = ehci_methods, + .size = sizeof(struct jz4780_ehci_softc), +}; + +static devclass_t ehci_devclass; + +DRIVER_MODULE(ehci, simplebus, ehci_driver, ehci_devclass, 0, 0); +MODULE_DEPEND(ehci, usb, 1, 1, 1); +MODULE_DEPEND(ehci, gpio, 1, 1, 1); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_ehci.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_gpio.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_gpio.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_gpio.c (revision 308868) @@ -0,0 +1,830 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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 +__FBSDID("$FreeBSD$"); + +#include "opt_platform.h" + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include +#include + +#include +#include + +#include "jz4780_gpio_if.h" +#include "gpio_if.h" +#include "pic_if.h" + +#define JZ4780_GPIO_PINS 32 + +enum pin_function { + JZ_FUNC_DEV_0, + JZ_FUNC_DEV_1, + JZ_FUNC_DEV_2, + JZ_FUNC_DEV_3, + JZ_FUNC_GPIO, + JZ_FUNC_INTR, +}; + +struct jz4780_gpio_pin { + struct intr_irqsrc pin_irqsrc; + enum intr_trigger intr_trigger; + enum intr_polarity intr_polarity; + enum pin_function pin_func; + uint32_t pin_caps; + uint32_t pin_flags; + uint32_t pin_num; + char pin_name[GPIOMAXNAME]; +}; + +struct jz4780_gpio_softc { + device_t dev; + device_t busdev; + struct resource *res[2]; + struct mtx mtx; + struct jz4780_gpio_pin pins[JZ4780_GPIO_PINS]; + void *intrhand; +}; + +static struct resource_spec jz4780_gpio_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static int jz4780_gpio_probe(device_t dev); +static int jz4780_gpio_attach(device_t dev); +static int jz4780_gpio_detach(device_t dev); +static int jz4780_gpio_intr(void *arg); + +#define JZ4780_GPIO_LOCK(sc) mtx_lock_spin(&(sc)->mtx) +#define JZ4780_GPIO_UNLOCK(sc) mtx_unlock_spin(&(sc)->mtx) +#define JZ4780_GPIO_LOCK_INIT(sc) \ + mtx_init(&(sc)->mtx, device_get_nameunit((sc)->dev), \ + "jz4780_gpio", MTX_SPIN) +#define JZ4780_GPIO_LOCK_DESTROY(sc) mtx_destroy(&(sc)->mtx); + +#define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], (reg), (val)) +#define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], (reg)) + +static int +jz4780_gpio_probe(device_t dev) +{ + phandle_t node; + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + /* We only like particular parent */ + if (!ofw_bus_is_compatible(device_get_parent(dev), + "ingenic,jz4780-pinctrl")) + return (ENXIO); + + /* ... and only specific children os that parent */ + node = ofw_bus_get_node(dev); + if (!OF_hasprop(node, "gpio-controller")) + return (ENXIO); + + device_set_desc(dev, "Ingenic JZ4780 GPIO Controller"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jz4780_gpio_pin_set_func(struct jz4780_gpio_softc *sc, uint32_t pin, + uint32_t func) +{ + uint32_t mask = (1u << pin); + + if (func > (uint32_t)JZ_FUNC_DEV_3) + return (EINVAL); + + CSR_WRITE_4(sc, JZ_GPIO_INTC, mask); + CSR_WRITE_4(sc, JZ_GPIO_MASKC, mask); + if (func & 2) + CSR_WRITE_4(sc, JZ_GPIO_PAT1S, mask); + else + CSR_WRITE_4(sc, JZ_GPIO_PAT1C, mask); + if (func & 1) + CSR_WRITE_4(sc, JZ_GPIO_PAT0S, mask); + else + CSR_WRITE_4(sc, JZ_GPIO_PAT0C, mask); + + sc->pins[pin].pin_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT); + sc->pins[pin].pin_func = (enum pin_function)func; + return (0); +} + +static int +jz4780_gpio_pin_set_direction(struct jz4780_gpio_softc *sc, + uint32_t pin, uint32_t dir) +{ + uint32_t mask = (1u << pin); + + switch (dir) { + case GPIO_PIN_OUTPUT: + if (sc->pins[pin].pin_caps & dir) + CSR_WRITE_4(sc, JZ_GPIO_PAT1C, mask); + else + return (EINVAL); + break; + case GPIO_PIN_INPUT: + if (sc->pins[pin].pin_caps & dir) + CSR_WRITE_4(sc, JZ_GPIO_PAT1S, mask); + else + return (EINVAL); + break; + } + + sc->pins[pin].pin_flags &= ~(GPIO_PIN_INPUT | GPIO_PIN_OUTPUT); + sc->pins[pin].pin_flags |= dir; + return (0); +} + +static int +jz4780_gpio_pin_set_bias(struct jz4780_gpio_softc *sc, + uint32_t pin, uint32_t bias) +{ + uint32_t mask = (1u << pin); + + switch (bias) { + case GPIO_PIN_PULLUP: + case GPIO_PIN_PULLDOWN: + if (sc->pins[pin].pin_caps & bias) + CSR_WRITE_4(sc, JZ_GPIO_DPULLC, mask); + else + return (EINVAL); + break; + case 0: + CSR_WRITE_4(sc, JZ_GPIO_DPULLS, mask); + break; + default: + return (ENOTSUP); + } + + sc->pins[pin].pin_flags &= ~(GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN); + sc->pins[pin].pin_flags |= bias; + return (0); +} + +/* + * Decode pin configuration using this map + */ +#if 0 +INT MASK PAT1 PAT0 +1 x 0 0 /* intr, level, low */ +1 x 0 1 /* intr, level, high */ +1 x 1 0 /* intr, edge, falling */ +1 x 1 1 /* intr, edge, rising */ +0 0 0 0 /* function, func 0 */ +0 0 0 1 /* function, func 1 */ +0 0 1 0 /* function, func 2 */ +0 0 1 0 /* function, func 3 */ +0 1 0 0 /* gpio, output 0 */ +0 1 0 1 /* gpio, output 1 */ +0 1 1 x /* gpio, input */ +#endif + +static void +jz4780_gpio_pin_probe(struct jz4780_gpio_softc *sc, uint32_t pin) +{ + uint32_t mask = (1u << pin); + uint32_t val; + + /* Clear cached gpio config */ + sc->pins[pin].pin_flags = 0; + + /* First check if pin is in interrupt mode */ + val = CSR_READ_4(sc, JZ_GPIO_INT); + if (val & mask) { + /* Pin is in interrupt mode, decode interrupt triggering mode */ + val = CSR_READ_4(sc, JZ_GPIO_PAT1); + if (val & mask) + sc->pins[pin].intr_trigger = INTR_TRIGGER_EDGE; + else + sc->pins[pin].intr_trigger = INTR_TRIGGER_LEVEL; + /* Decode interrupt polarity */ + val = CSR_READ_4(sc, JZ_GPIO_PAT0); + if (val & mask) + sc->pins[pin].intr_polarity = INTR_POLARITY_HIGH; + else + sc->pins[pin].intr_polarity = INTR_POLARITY_LOW; + + sc->pins[pin].pin_func = JZ_FUNC_INTR; + sc->pins[pin].pin_flags = 0; + return; + } + /* Next check if pin is in gpio mode */ + val = CSR_READ_4(sc, JZ_GPIO_MASK); + if (val & mask) { + /* Pin is in gpio mode, decode direction and bias */ + val = CSR_READ_4(sc, JZ_GPIO_PAT1); + if (val & mask) + sc->pins[pin].pin_flags |= GPIO_PIN_INPUT; + else + sc->pins[pin].pin_flags |= GPIO_PIN_OUTPUT; + /* Check for bias */ + val = CSR_READ_4(sc, JZ_GPIO_DPULL); + if ((val & mask) == 0) + sc->pins[pin].pin_flags |= sc->pins[pin].pin_caps & + (GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN); + sc->pins[pin].pin_func = JZ_FUNC_GPIO; + return; + } + /* By exclusion, pin is in alternate function mode */ + val = CSR_READ_4(sc, JZ_GPIO_DPULL); + if ((val & mask) == 0) + sc->pins[pin].pin_flags = sc->pins[pin].pin_caps & + (GPIO_PIN_PULLUP | GPIO_PIN_PULLDOWN); + val = ((CSR_READ_4(sc, JZ_GPIO_PAT1) & mask) >> pin) << 1; + val = val | ((CSR_READ_4(sc, JZ_GPIO_PAT1) & mask) >> pin); + sc->pins[pin].pin_func = (enum pin_function)val; +} + +static int +jz4780_gpio_register_isrcs(struct jz4780_gpio_softc *sc) +{ + int error; + uint32_t irq, i; + struct intr_irqsrc *isrc; + const char *name; + + name = device_get_nameunit(sc->dev); + for (irq = 0; irq < JZ4780_GPIO_PINS; irq++) { + isrc = &sc->pins[irq].pin_irqsrc; + error = intr_isrc_register(isrc, sc->dev, 0, "%s,%d", + name, irq); + if (error != 0) { + for (i = 0; i < irq; i++) + intr_isrc_deregister(&sc->pins[i].pin_irqsrc); + device_printf(sc->dev, "%s failed", __func__); + return (error); + } + } + + return (0); +} + +static int +jz4780_gpio_attach(device_t dev) +{ + struct jz4780_gpio_softc *sc = device_get_softc(dev); + phandle_t node; + uint32_t i, pd_pins, pu_pins; + + sc->dev = dev; + + if (bus_alloc_resources(dev, jz4780_gpio_spec, sc->res)) { + device_printf(dev, "could not allocate resources for device\n"); + return (ENXIO); + } + + JZ4780_GPIO_LOCK_INIT(sc); + + node = ofw_bus_get_node(dev); + OF_getencprop(node, "ingenic,pull-ups", &pu_pins, sizeof(pu_pins)); + OF_getencprop(node, "ingenic,pull-downs", &pd_pins, sizeof(pd_pins)); + + for (i = 0; i < JZ4780_GPIO_PINS; i++) { + sc->pins[i].pin_num = i; + sc->pins[i].pin_caps |= GPIO_PIN_INPUT | GPIO_PIN_OUTPUT; + if (pu_pins & (1 << i)) + sc->pins[i].pin_caps |= GPIO_PIN_PULLUP; + if (pd_pins & (1 << i)) + sc->pins[i].pin_caps |= GPIO_PIN_PULLDOWN; + sc->pins[i].intr_polarity = INTR_POLARITY_CONFORM; + sc->pins[i].intr_trigger = INTR_TRIGGER_CONFORM; + + snprintf(sc->pins[i].pin_name, GPIOMAXNAME - 1, "gpio%c%d", + device_get_unit(dev) + 'a', i); + sc->pins[i].pin_name[GPIOMAXNAME - 1] = '\0'; + + jz4780_gpio_pin_probe(sc, i); + } + + if (jz4780_gpio_register_isrcs(sc) != 0) + goto fail; + + if (intr_pic_register(dev, OF_xref_from_node(node)) == NULL) { + device_printf(dev, "could not register PIC\n"); + goto fail; + } + + if (bus_setup_intr(dev, sc->res[1], INTR_TYPE_MISC | INTR_MPSAFE, + jz4780_gpio_intr, NULL, sc, &sc->intrhand) != 0) + goto fail_pic; + + sc->busdev = gpiobus_attach_bus(dev); + if (sc->busdev == NULL) + goto fail_pic; + + return (0); +fail_pic: + intr_pic_deregister(dev, OF_xref_from_node(node)); +fail: + if (sc->intrhand != NULL) + bus_teardown_intr(dev, sc->res[1], sc->intrhand); + bus_release_resources(dev, jz4780_gpio_spec, sc->res); + JZ4780_GPIO_LOCK_DESTROY(sc); + return (ENXIO); +} + +static int +jz4780_gpio_detach(device_t dev) +{ + struct jz4780_gpio_softc *sc = device_get_softc(dev); + + bus_release_resources(dev, jz4780_gpio_spec, sc->res); + JZ4780_GPIO_LOCK_DESTROY(sc); + return (0); +} + +static int +jz4780_gpio_configure_pin(device_t dev, uint32_t pin, uint32_t func, + uint32_t flags) +{ + struct jz4780_gpio_softc *sc; + int retval; + + if (pin >= JZ4780_GPIO_PINS) + return (EINVAL); + + sc = device_get_softc(dev); + JZ4780_GPIO_LOCK(sc); + retval = jz4780_gpio_pin_set_func(sc, pin, func); + if (retval == 0) + retval = jz4780_gpio_pin_set_bias(sc, pin, flags); + JZ4780_GPIO_UNLOCK(sc); + return (retval); +} + +static device_t +jz4780_gpio_get_bus(device_t dev) +{ + struct jz4780_gpio_softc *sc; + + sc = device_get_softc(dev); + + return (sc->busdev); +} + +static int +jz4780_gpio_pin_max(device_t dev, int *maxpin) +{ + + *maxpin = JZ4780_GPIO_PINS - 1; + return (0); +} + +static int +jz4780_gpio_pin_getcaps(device_t dev, uint32_t pin, uint32_t *caps) +{ + struct jz4780_gpio_softc *sc; + + if (pin >= JZ4780_GPIO_PINS) + return (EINVAL); + + sc = device_get_softc(dev); + JZ4780_GPIO_LOCK(sc); + *caps = sc->pins[pin].pin_caps; + JZ4780_GPIO_UNLOCK(sc); + + return (0); +} + +static int +jz4780_gpio_pin_getflags(device_t dev, uint32_t pin, uint32_t *flags) +{ + struct jz4780_gpio_softc *sc; + + if (pin >= JZ4780_GPIO_PINS) + return (EINVAL); + + sc = device_get_softc(dev); + JZ4780_GPIO_LOCK(sc); + *flags = sc->pins[pin].pin_flags; + JZ4780_GPIO_UNLOCK(sc); + + return (0); +} + +static int +jz4780_gpio_pin_getname(device_t dev, uint32_t pin, char *name) +{ + struct jz4780_gpio_softc *sc; + + if (pin >= JZ4780_GPIO_PINS) + return (EINVAL); + + sc = device_get_softc(dev); + strncpy(name, sc->pins[pin].pin_name, GPIOMAXNAME - 1); + name[GPIOMAXNAME - 1] = '\0'; + + return (0); +} + +static int +jz4780_gpio_pin_setflags(device_t dev, uint32_t pin, uint32_t flags) +{ + struct jz4780_gpio_softc *sc; + int retval; + + if (pin >= JZ4780_GPIO_PINS) + return (EINVAL); + + sc = device_get_softc(dev); + JZ4780_GPIO_LOCK(sc); + retval = jz4780_gpio_pin_set_direction(sc, pin, + flags & (GPIO_PIN_INPUT | GPIO_PIN_OUTPUT)); + if (retval == 0) + retval = jz4780_gpio_pin_set_bias(sc, pin, + flags & (GPIO_PIN_PULLDOWN | GPIO_PIN_PULLUP)); + JZ4780_GPIO_UNLOCK(sc); + + return (retval); +} + +static int +jz4780_gpio_pin_set(device_t dev, uint32_t pin, unsigned int value) +{ + struct jz4780_gpio_softc *sc; + uint32_t mask; + int retval; + + if (pin >= JZ4780_GPIO_PINS) + return (EINVAL); + + retval = EINVAL; + mask = (1u << pin); + sc = device_get_softc(dev); + JZ4780_GPIO_LOCK(sc); + if (sc->pins[pin].pin_func == JZ_FUNC_GPIO) { + CSR_WRITE_4(sc, value ? JZ_GPIO_PAT0S : JZ_GPIO_PAT0C, mask); + retval = 0; + } + JZ4780_GPIO_UNLOCK(sc); + + return (retval); +} + +static int +jz4780_gpio_pin_get(device_t dev, uint32_t pin, unsigned int *val) +{ + struct jz4780_gpio_softc *sc; + uint32_t data, mask; + + if (pin >= JZ4780_GPIO_PINS) + return (EINVAL); + + mask = (1u << pin); + sc = device_get_softc(dev); + JZ4780_GPIO_LOCK(sc); + data = CSR_READ_4(sc, JZ_GPIO_PIN); + JZ4780_GPIO_UNLOCK(sc); + *val = (data & mask) ? 1 : 0; + + return (0); +} + +static int +jz4780_gpio_pin_toggle(device_t dev, uint32_t pin) +{ + struct jz4780_gpio_softc *sc; + uint32_t data, mask; + int retval; + + if (pin >= JZ4780_GPIO_PINS) + return (EINVAL); + + retval = EINVAL; + mask = (1u << pin); + sc = device_get_softc(dev); + JZ4780_GPIO_LOCK(sc); + if (sc->pins[pin].pin_func == JZ_FUNC_GPIO && + sc->pins[pin].pin_flags & GPIO_PIN_OUTPUT) { + data = CSR_READ_4(sc, JZ_GPIO_PIN); + CSR_WRITE_4(sc, (data & mask) ? JZ_GPIO_PAT0C : JZ_GPIO_PAT0S, + mask); + retval = 0; + } + JZ4780_GPIO_UNLOCK(sc); + + return (retval); +} + +#ifdef FDT +static int +jz_gpio_map_intr_fdt(device_t dev, struct intr_map_data *data, u_int *irqp, + enum intr_polarity *polp, enum intr_trigger *trigp) +{ + struct jz4780_gpio_softc *sc; + struct intr_map_data_fdt *daf; + + sc = device_get_softc(dev); + daf = (struct intr_map_data_fdt *)data; + + if (data == NULL || data->type != INTR_MAP_DATA_FDT || + daf->ncells == 0 || daf->ncells > 2) + return (EINVAL); + + *irqp = daf->cells[0]; + if (daf->ncells == 1) { + *trigp = INTR_TRIGGER_CONFORM; + *polp = INTR_POLARITY_CONFORM; + return (0); + } + + switch (daf->cells[1]) + { + case IRQ_TYPE_EDGE_RISING: + *trigp = INTR_TRIGGER_EDGE; + *polp = INTR_POLARITY_HIGH; + break; + case IRQ_TYPE_EDGE_FALLING: + *trigp = INTR_TRIGGER_EDGE; + *polp = INTR_POLARITY_LOW; + break; + case IRQ_TYPE_LEVEL_HIGH: + *trigp = INTR_TRIGGER_LEVEL; + *polp = INTR_POLARITY_HIGH; + break; + case IRQ_TYPE_LEVEL_LOW: + *trigp = INTR_TRIGGER_LEVEL; + *polp = INTR_POLARITY_LOW; + break; + default: + device_printf(sc->dev, "unsupported trigger/polarity 0x%2x\n", + daf->cells[1]); + return (ENOTSUP); + } + + return (0); +} +#endif + +static int +jz_gpio_map_intr(device_t dev, struct intr_map_data *data, u_int *irqp, + enum intr_polarity *polp, enum intr_trigger *trigp) +{ + struct jz4780_gpio_softc *sc; + enum intr_polarity pol; + enum intr_trigger trig; + u_int irq; + + sc = device_get_softc(dev); + switch (data->type) { +#ifdef FDT + case INTR_MAP_DATA_FDT: + if (jz_gpio_map_intr_fdt(dev, data, &irq, &pol, &trig) != 0) + return (EINVAL); + break; +#endif + default: + return (EINVAL); + } + + if (irq >= nitems(sc->pins)) + return (EINVAL); + + *irqp = irq; + if (polp != NULL) + *polp = pol; + if (trigp != NULL) + *trigp = trig; + return (0); +} + +static int +jz4780_gpio_pic_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) +{ + struct jz4780_gpio_softc *sc; + int retval; + u_int irq; + + retval = jz_gpio_map_intr(dev, data, &irq, NULL, NULL); + if (retval == 0) { + sc = device_get_softc(dev); + *isrcp = &sc->pins[irq].pin_irqsrc; + } + return (retval); +} + +static int +jz4780_gpio_pic_setup_intr(device_t dev, struct intr_irqsrc *isrc, + struct resource *res, struct intr_map_data *data) +{ + struct jz4780_gpio_softc *sc; + struct jz4780_gpio_pin *pin; + enum intr_polarity pol; + enum intr_trigger trig; + uint32_t mask, irq; + + if (data == NULL) + return (ENOTSUP); + + /* Get config for resource. */ + if (jz_gpio_map_intr(dev, data, &irq, &pol, &trig)) + return (EINVAL); + + pin = __containerof(isrc, struct jz4780_gpio_pin, pin_irqsrc); + if (isrc != &pin->pin_irqsrc) + return (EINVAL); + + /* Compare config if this is not first setup. */ + if (isrc->isrc_handlers != 0) { + if ((pol != INTR_POLARITY_CONFORM && pol != pin->intr_polarity) || + (trig != INTR_TRIGGER_CONFORM && trig != pin->intr_trigger)) + return (EINVAL); + else + return (0); + } + + if (pol == INTR_POLARITY_CONFORM) + pol = INTR_POLARITY_LOW; /* just pick some */ + if (trig == INTR_TRIGGER_CONFORM) + trig = INTR_TRIGGER_EDGE; /* just pick some */ + + sc = device_get_softc(dev); + mask = 1u << pin->pin_num; + + JZ4780_GPIO_LOCK(sc); + CSR_WRITE_4(sc, JZ_GPIO_MASKS, mask); + CSR_WRITE_4(sc, JZ_GPIO_INTS, mask); + + if (trig == INTR_TRIGGER_LEVEL) + CSR_WRITE_4(sc, JZ_GPIO_PAT1C, mask); + else + CSR_WRITE_4(sc, JZ_GPIO_PAT1S, mask); + + if (pol == INTR_POLARITY_LOW) + CSR_WRITE_4(sc, JZ_GPIO_PAT0C, mask); + else + CSR_WRITE_4(sc, JZ_GPIO_PAT0S, mask); + + pin->pin_func = JZ_FUNC_INTR; + pin->intr_trigger = trig; + pin->intr_polarity = pol; + + CSR_WRITE_4(sc, JZ_GPIO_FLAGC, mask); + CSR_WRITE_4(sc, JZ_GPIO_MASKC, mask); + JZ4780_GPIO_UNLOCK(sc); + return (0); +} + +static void +jz4780_gpio_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct jz4780_gpio_softc *sc; + struct jz4780_gpio_pin *pin; + + sc = device_get_softc(dev); + pin = __containerof(isrc, struct jz4780_gpio_pin, pin_irqsrc); + + CSR_WRITE_4(sc, JZ_GPIO_MASKC, 1u << pin->pin_num); +} + +static void +jz4780_gpio_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct jz4780_gpio_softc *sc; + struct jz4780_gpio_pin *pin; + + sc = device_get_softc(dev); + pin = __containerof(isrc, struct jz4780_gpio_pin, pin_irqsrc); + + CSR_WRITE_4(sc, JZ_GPIO_MASKS, 1u << pin->pin_num); +} + +static void +jz4780_gpio_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + jz4780_gpio_pic_disable_intr(dev, isrc); +} + +static void +jz4780_gpio_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + jz4780_gpio_pic_enable_intr(dev, isrc); +} + +static void +jz4780_gpio_pic_post_filter(device_t dev, struct intr_irqsrc *isrc) +{ + struct jz4780_gpio_softc *sc; + struct jz4780_gpio_pin *pin; + + sc = device_get_softc(dev); + pin = __containerof(isrc, struct jz4780_gpio_pin, pin_irqsrc); + + CSR_WRITE_4(sc, JZ_GPIO_FLAGC, 1u << pin->pin_num); +} + +static int +jz4780_gpio_intr(void *arg) +{ + struct jz4780_gpio_softc *sc; + uint32_t i, interrupts; + + sc = arg; + interrupts = CSR_READ_4(sc, JZ_GPIO_FLAG); + + for (i = 0; interrupts != 0; i++, interrupts >>= 1) { + if ((interrupts & 0x1) == 0) + continue; + if (intr_isrc_dispatch(&sc->pins[i].pin_irqsrc, + curthread->td_intr_frame) != 0) { + device_printf(sc->dev, "spurious interrupt %d\n", i); + PIC_DISABLE_INTR(sc->dev, &sc->pins[i].pin_irqsrc); + } + } + + return (FILTER_HANDLED); +} + +static device_method_t jz4780_gpio_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_gpio_probe), + DEVMETHOD(device_attach, jz4780_gpio_attach), + DEVMETHOD(device_detach, jz4780_gpio_detach), + + /* GPIO protocol */ + DEVMETHOD(gpio_get_bus, jz4780_gpio_get_bus), + DEVMETHOD(gpio_pin_max, jz4780_gpio_pin_max), + DEVMETHOD(gpio_pin_getname, jz4780_gpio_pin_getname), + DEVMETHOD(gpio_pin_getflags, jz4780_gpio_pin_getflags), + DEVMETHOD(gpio_pin_getcaps, jz4780_gpio_pin_getcaps), + DEVMETHOD(gpio_pin_setflags, jz4780_gpio_pin_setflags), + DEVMETHOD(gpio_pin_get, jz4780_gpio_pin_get), + DEVMETHOD(gpio_pin_set, jz4780_gpio_pin_set), + DEVMETHOD(gpio_pin_toggle, jz4780_gpio_pin_toggle), + + /* Custom interface to set pin function */ + DEVMETHOD(jz4780_gpio_configure_pin, jz4780_gpio_configure_pin), + + /* Interrupt controller interface */ + DEVMETHOD(pic_setup_intr, jz4780_gpio_pic_setup_intr), + DEVMETHOD(pic_enable_intr, jz4780_gpio_pic_enable_intr), + DEVMETHOD(pic_disable_intr, jz4780_gpio_pic_disable_intr), + DEVMETHOD(pic_map_intr, jz4780_gpio_pic_map_intr), + DEVMETHOD(pic_post_filter, jz4780_gpio_pic_post_filter), + DEVMETHOD(pic_post_ithread, jz4780_gpio_pic_post_ithread), + DEVMETHOD(pic_pre_ithread, jz4780_gpio_pic_pre_ithread), + + DEVMETHOD_END +}; + +static driver_t jz4780_gpio_driver = { + "gpio", + jz4780_gpio_methods, + sizeof(struct jz4780_gpio_softc), +}; + +static devclass_t jz4780_gpio_devclass; + +EARLY_DRIVER_MODULE(jz4780_gpio, simplebus, jz4780_gpio_driver, + jz4780_gpio_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_gpio.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_gpio_if.m =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_gpio_if.m (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_gpio_if.m (revision 308868) @@ -0,0 +1,41 @@ +#- +# Copyright (c) 2015 Alexander Kabaev +# 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. +# +# $FreeBSD$ +# + +#include + +INTERFACE jz4780_gpio; + +/** + * Configures pin as specified by FDT pinctrl entry + */ +METHOD int configure_pin { + device_t dev; + uint32_t gpio; + uint32_t func; + uint32_t flags; +}; Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_gpio_if.m ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_intr.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_intr.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_intr.c (revision 308868) @@ -0,0 +1,333 @@ +/*- + * Copyright (c) 2015 Alexander Kabaev + * 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, immediately at the beginning of the file. + * 2. The name of the author may not be used to endorse or promote products + * derived from this software without specific prior written permission. + * + * 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 "opt_platform.h" + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "pic_if.h" + +#define JZ4780_NIRQS 64 + +static int jz4780_pic_intr(void *); + +struct jz4780_pic_isrc { + struct intr_irqsrc isrc; + u_int irq; +}; + +struct jz4780_pic_softc { + device_t pic_dev; + void * pic_intrhand; + struct resource * pic_res[2]; + struct jz4780_pic_isrc pic_irqs[JZ4780_NIRQS]; + uint32_t nirqs; +}; + +#define PIC_INTR_ISRC(sc, irq) (&(sc)->pic_irqs[(irq)].isrc) + +static struct resource_spec jz4780_pic_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, /* Registers */ + { SYS_RES_IRQ, 0, RF_ACTIVE }, /* Parent interrupt */ + { -1, 0 } +}; + +static struct ofw_compat_data compat_data[] = { + {"ingenic,jz4780-intc", true}, + {NULL, false} +}; + +#define READ4(_sc, _reg) bus_read_4((_sc)->pic_res[0], _reg) +#define WRITE4(_sc, _reg, _val) bus_write_4((_sc)->pic_res[0], _reg, _val) + +static int +jz4780_pic_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_search_compatible(dev, compat_data)->ocd_data) + return (ENXIO); + device_set_desc(dev, "JZ4780 Interrupt Controller"); + return (BUS_PROBE_DEFAULT); +} + +static inline void +pic_irq_unmask(struct jz4780_pic_softc *sc, u_int irq) +{ + if (irq < 32) + WRITE4(sc, JZ_ICMCR0, (1u << irq)); + else + WRITE4(sc, JZ_ICMCR1, (1u << (irq - 32))); +} + +static inline void +pic_irq_mask(struct jz4780_pic_softc *sc, u_int irq) +{ + if (irq < 32) + WRITE4(sc, JZ_ICMSR0, (1u << irq)); + else + WRITE4(sc, JZ_ICMSR1, (1u << (irq - 32))); +} + +static inline intptr_t +pic_xref(device_t dev) +{ + return (OF_xref_from_node(ofw_bus_get_node(dev))); +} + +static int +jz4780_pic_register_isrcs(struct jz4780_pic_softc *sc) +{ + int error; + uint32_t irq, i; + struct intr_irqsrc *isrc; + const char *name; + + name = device_get_nameunit(sc->pic_dev); + for (irq = 0; irq < sc->nirqs; irq++) { + sc->pic_irqs[irq].irq = irq; + isrc = PIC_INTR_ISRC(sc, irq); + error = intr_isrc_register(isrc, sc->pic_dev, 0, "%s,%d", + name, irq); + if (error != 0) { + for (i = 0; i < irq; i++) + intr_isrc_deregister(PIC_INTR_ISRC(sc, irq)); + device_printf(sc->pic_dev, "%s failed", __func__); + return (error); + } + } + + return (0); +} + +static int +jz4780_pic_attach(device_t dev) +{ + struct jz4780_pic_softc *sc; + intptr_t xref; + + xref = pic_xref(dev); + + sc = device_get_softc(dev); + + if (bus_alloc_resources(dev, jz4780_pic_spec, sc->pic_res)) { + device_printf(dev, "could not allocate resources\n"); + return (ENXIO); + } + + sc->pic_dev = dev; + + /* Set the number of interrupts */ + sc->nirqs = nitems(sc->pic_irqs); + + /* Mask all interrupts */ + WRITE4(sc, JZ_ICMR0, 0xFFFFFFFF); + WRITE4(sc, JZ_ICMR1, 0xFFFFFFFF); + + /* Register the interrupts */ + if (jz4780_pic_register_isrcs(sc) != 0) { + device_printf(dev, "could not register PIC ISRCs\n"); + goto cleanup; + } + + /* + * Now, when everything is initialized, it's right time to + * register interrupt controller to interrupt framefork. + */ + if (intr_pic_register(dev, xref) == NULL) { + device_printf(dev, "could not register PIC\n"); + goto cleanup; + } + + if (bus_setup_intr(dev, sc->pic_res[1], INTR_TYPE_CLK, + jz4780_pic_intr, NULL, sc, &sc->pic_intrhand)) { + device_printf(dev, "could not setup irq handler\n"); + intr_pic_deregister(dev, xref); + goto cleanup; + } + + return (0); + +cleanup: + bus_release_resources(dev, jz4780_pic_spec, sc->pic_res); + + return(ENXIO); +} + +static int +jz4780_pic_intr(void *arg) +{ + struct jz4780_pic_softc *sc = arg; + struct intr_irqsrc *isrc; + struct thread *td; + uint32_t i, intr; + + td = curthread; + /* Workaround: do not inflate intr nesting level */ + td->td_intr_nesting_level--; + + intr = READ4(sc, JZ_ICPR0); + while ((i = fls(intr)) != 0) { + i--; + intr &= ~(1u << i); + + isrc = PIC_INTR_ISRC(sc, i); + if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) { + device_printf(sc->pic_dev, "Stray interrupt %u detected\n", i); + pic_irq_mask(sc, i); + continue; + } + } + + KASSERT(i == 0, ("all interrupts handled")); + + intr = READ4(sc, JZ_ICPR1); + while ((i = fls(intr)) != 0) { + i--; + intr &= ~(1u << i); + i += 32; + + isrc = PIC_INTR_ISRC(sc, i); + if (intr_isrc_dispatch(isrc, curthread->td_intr_frame) != 0) { + device_printf(sc->pic_dev, "Stray interrupt %u detected\n", i); + pic_irq_mask(sc, i); + continue; + } + } + + KASSERT(i == 0, ("all interrupts handled")); + td->td_intr_nesting_level++; + + return (FILTER_HANDLED); +} + +static int +jz4780_pic_map_intr(device_t dev, struct intr_map_data *data, + struct intr_irqsrc **isrcp) +{ +#ifdef FDT + struct jz4780_pic_softc *sc; + struct intr_map_data_fdt *daf; + + sc = device_get_softc(dev); + daf = (struct intr_map_data_fdt *)data; + + if (data == NULL || data->type != INTR_MAP_DATA_FDT || + daf->ncells != 1 || daf->cells[0] >= sc->nirqs) + return (EINVAL); + + *isrcp = PIC_INTR_ISRC(sc, daf->cells[0]); + return (0); +#else + return (EINVAL); +#endif +} + +static void +jz4780_pic_enable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct jz4780_pic_isrc *pic_isrc; + + pic_isrc = (struct jz4780_pic_isrc *)isrc; + pic_irq_unmask(device_get_softc(dev), pic_isrc->irq); +} + +static void +jz4780_pic_disable_intr(device_t dev, struct intr_irqsrc *isrc) +{ + struct jz4780_pic_isrc *pic_isrc; + + pic_isrc = (struct jz4780_pic_isrc *)isrc; + pic_irq_mask(device_get_softc(dev), pic_isrc->irq); +} + +static void +jz4780_pic_pre_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + jz4780_pic_disable_intr(dev, isrc); +} + +static void +jz4780_pic_post_ithread(device_t dev, struct intr_irqsrc *isrc) +{ + + jz4780_pic_enable_intr(dev, isrc); +} + +static device_method_t jz4780_pic_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_pic_probe), + DEVMETHOD(device_attach, jz4780_pic_attach), + /* Interrupt controller interface */ + DEVMETHOD(pic_enable_intr, jz4780_pic_enable_intr), + DEVMETHOD(pic_disable_intr, jz4780_pic_disable_intr), + DEVMETHOD(pic_map_intr, jz4780_pic_map_intr), + DEVMETHOD(pic_post_ithread, jz4780_pic_post_ithread), + DEVMETHOD(pic_pre_ithread, jz4780_pic_pre_ithread), + { 0, 0 } +}; + +static driver_t jz4780_pic_driver = { + "intc", + jz4780_pic_methods, + sizeof(struct jz4780_pic_softc), +}; + +static devclass_t jz4780_pic_devclass; + +EARLY_DRIVER_MODULE(intc, ofwbus, jz4780_pic_driver, jz4780_pic_devclass, 0, 0, + BUS_PASS_INTERRUPT + BUS_PASS_ORDER_MIDDLE); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_intr.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_machdep.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_machdep.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_machdep.c (revision 308868) @@ -0,0 +1,296 @@ +/*- + * Copyright (c) 2009 Oleksandr Tymoshenko + * Copyright (c) 2015 Alexander Kabaev + * 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 +__FBSDID("$FreeBSD$"); + +#include "opt_ddb.h" +#include "opt_platform.h" + +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef FDT +#include +#include +#endif + +#include +#include + +#include + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +uint32_t * const led = (uint32_t *)0xb0010548; + +extern char edata[], end[]; +static char boot1_env[4096]; + +void +platform_cpu_init(void) +{ + uint32_t reg; + + /* + * Do not expect mbox interrups while writing + * mbox + */ + reg = mips_rd_xburst_reim(); + reg &= ~JZ_REIM_MIRQ0M; + mips_wr_xburst_reim(reg); + + /* Clean mailboxes */ + mips_wr_xburst_mbox0(0); + mips_wr_xburst_mbox1(0); + mips_wr_xburst_core_sts(~JZ_CORESTS_MIRQ0P); + + /* Unmask mbox interrupts */ + reg |= JZ_REIM_MIRQ0M; + mips_wr_xburst_reim(reg); +} + +void +platform_reset(void) +{ + /* + * For now, provoke a watchdog reset in about a second, so UART buffers + * have a fighting chance to flush before we pull the plug + */ + writereg(JZ_TCU_BASE + JZ_WDOG_TCER, 0); /* disable watchdog */ + writereg(JZ_TCU_BASE + JZ_WDOG_TCNT, 0); /* reset counter */ + writereg(JZ_TCU_BASE + JZ_WDOG_TDR, 128); /* wait for ~1s */ + writereg(JZ_TCU_BASE + JZ_WDOG_TCSR, TCSR_RTC_EN | TCSR_DIV_256); + writereg(JZ_TCU_BASE + JZ_WDOG_TCER, TCER_ENABLE); /* fire! */ + + /* Wait for reset */ + while (1) + ; +} + +static void +mips_init(void) +{ + int i; +#ifdef FDT + struct mem_region mr[FDT_MEM_REGIONS]; + uint64_t val; + int mr_cnt; + int j; +#endif + + for (i = 0; i < 10; i++) { + phys_avail[i] = 0; + } + + /* The minimal amount of memory Ingenic SoC can have. */ + dump_avail[0] = phys_avail[0] = MIPS_KSEG0_TO_PHYS(kernel_kseg0_end); + physmem = realmem = btoc(32 * 1024 * 1024); + + /* + * X1000 mips cpu special. + * TODO: do anyone know what is this ? + */ + __asm( + "li $2, 0xa9000000 \n\t" + "mtc0 $2, $5, 4 \n\t" + "nop \n\t" + ::"r"(2)); + +#ifdef FDT + if (fdt_get_mem_regions(mr, &mr_cnt, &val) == 0) { + + physmem = realmem = btoc(val); + + KASSERT((phys_avail[0] >= mr[0].mr_start) && \ + (phys_avail[0] < (mr[0].mr_start + mr[0].mr_size)), + ("First region is not within FDT memory range")); + + /* Limit size of the first region */ + phys_avail[1] = (mr[0].mr_start + MIN(mr[0].mr_size, ctob(realmem))); + dump_avail[1] = phys_avail[1]; + + /* Add the rest of regions */ + for (i = 1, j = 2; i < mr_cnt; i++, j+=2) { + phys_avail[j] = mr[i].mr_start; + phys_avail[j+1] = (mr[i].mr_start + mr[i].mr_size); + dump_avail[j] = phys_avail[j]; + dump_avail[j+1] = phys_avail[j+1]; + } + } +#endif + + init_param1(); + init_param2(physmem); + mips_cpu_init(); + pmap_bootstrap(); + mips_proc0_init(); + mutex_init(); + kdb_init(); + led[0] = 0x8000; +#ifdef KDB + if (boothowto & RB_KDB) + kdb_enter(KDB_WHY_BOOTFLAGS, "Boot flags requested debugger"); +#endif +} + +static void +_parse_bootarg(char *v) +{ + char *n; + + if (*v == '-') { + while (*v != '\0') { + v++; + switch (*v) { + case 'a': boothowto |= RB_ASKNAME; break; + /* Someone should simulate that ;-) */ + case 'C': boothowto |= RB_CDROM; break; + case 'd': boothowto |= RB_KDB; break; + case 'D': boothowto |= RB_MULTIPLE; break; + case 'm': boothowto |= RB_MUTE; break; + case 'g': boothowto |= RB_GDB; break; + case 'h': boothowto |= RB_SERIAL; break; + case 'p': boothowto |= RB_PAUSE; break; + case 'r': boothowto |= RB_DFLTROOT; break; + case 's': boothowto |= RB_SINGLE; break; + case 'v': boothowto |= RB_VERBOSE; break; + } + } + } else { + n = strsep(&v, "="); + if (v == NULL) + kern_setenv(n, "1"); + else + kern_setenv(n, v); + } +} + +static void +_parse_cmdline(int argc, char *argv[]) +{ + int i; + + for (i = 1; i < argc; i++) + _parse_bootarg(argv[i]); +} + +#ifdef FDT +/* Parse cmd line args as env - copied from xlp_machdep. */ +/* XXX-BZ this should really be centrally provided for all (boot) code. */ +static void +_parse_bootargs(char *cmdline) +{ + char *v; + + while ((v = strsep(&cmdline, " \n")) != NULL) { + if (*v == '\0') + continue; + _parse_bootarg(v); + } +} +#endif + +void +platform_start(__register_t a0, __register_t a1, + __register_t a2 __unused, __register_t a3 __unused) +{ + char **argv; + int argc; + vm_offset_t kernend; +#ifdef FDT + vm_offset_t dtbp; + phandle_t chosen; + char buf[2048]; /* early stack supposedly big enough */ +#endif + /* + * clear the BSS and SBSS segments, this should be first call in + * the function + */ + kernend = (vm_offset_t)&end; + memset(&edata, 0, kernend - (vm_offset_t)(&edata)); + + mips_postboot_fixup(); + + /* Initialize pcpu stuff */ + mips_pcpu0_init(); + + /* Something to hold kernel env until kmem is available */ + init_static_kenv(boot1_env, sizeof(boot1_env)); +#ifdef FDT + /* + * Find the dtb passed in by the boot loader (currently fictional). + */ + dtbp = (vm_offset_t)NULL; + +#if defined(FDT_DTB_STATIC) + /* + * In case the device tree blob was not retrieved (from metadata) try + * to use the statically embedded one. + */ + if (dtbp == (vm_offset_t)NULL) + dtbp = (vm_offset_t)&fdt_static_dtb; +#else +#error "Non-static FDT not supported on JZ4780" +#endif + if (OF_install(OFW_FDT, 0) == FALSE) + while (1); + if (OF_init((void *)dtbp) != 0) + while (1); +#endif + + cninit(); +#ifdef FDT + /* + * Get bootargs from FDT if specified. + */ + chosen = OF_finddevice("/chosen"); + if (OF_getprop(chosen, "bootargs", buf, sizeof(buf)) != -1) + _parse_bootargs(buf); +#endif + /* Parse cmdline from U-Boot */ + argc = a0; + argv = (char **)a1; + _parse_cmdline(argc, argv); + + mips_init(); +} Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_machdep.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_mmc.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_mmc.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_mmc.c (revision 308868) @@ -0,0 +1,1002 @@ +/*- + * Copyright (c) 2015 Alexander Kabaev + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#undef JZ_MMC_DEBUG + +#define JZ_MSC_MEMRES 0 +#define JZ_MSC_IRQRES 1 +#define JZ_MSC_RESSZ 2 +#define JZ_MSC_DMA_SEGS 128 +#define JZ_MSC_DMA_MAX_SIZE MAXPHYS + +#define JZ_MSC_INT_ERR_BITS (JZ_INT_CRC_RES_ERR | JZ_INT_CRC_READ_ERR | \ + JZ_INT_CRC_WRITE_ERR | JZ_INT_TIMEOUT_RES | \ + JZ_INT_TIMEOUT_READ) +static int jz4780_mmc_pio_mode = 0; + +TUNABLE_INT("hw.jz.mmc.pio_mode", &jz4780_mmc_pio_mode); + +struct jz4780_mmc_dma_desc { + uint32_t dma_next; + uint32_t dma_phys; + uint32_t dma_len; + uint32_t dma_cmd; +}; + +struct jz4780_mmc_softc { + bus_space_handle_t sc_bsh; + bus_space_tag_t sc_bst; + device_t sc_dev; + clk_t sc_clk; + int sc_bus_busy; + int sc_resid; + int sc_timeout; + struct callout sc_timeoutc; + struct mmc_host sc_host; + struct mmc_request * sc_req; + struct mtx sc_mtx; + struct resource * sc_res[JZ_MSC_RESSZ]; + uint32_t sc_intr_seen; + uint32_t sc_intr_mask; + uint32_t sc_intr_wait; + void * sc_intrhand; + uint32_t sc_cmdat; + + /* Fields required for DMA access. */ + bus_addr_t sc_dma_desc_phys; + bus_dmamap_t sc_dma_map; + bus_dma_tag_t sc_dma_tag; + void * sc_dma_desc; + bus_dmamap_t sc_dma_buf_map; + bus_dma_tag_t sc_dma_buf_tag; + int sc_dma_inuse; + int sc_dma_map_err; + uint32_t sc_dma_ctl; +}; + +static struct resource_spec jz4780_mmc_res_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE | RF_SHAREABLE }, + { -1, 0, 0 } +}; + +static int jz4780_mmc_probe(device_t); +static int jz4780_mmc_attach(device_t); +static int jz4780_mmc_detach(device_t); +static int jz4780_mmc_setup_dma(struct jz4780_mmc_softc *); +static int jz4780_mmc_reset(struct jz4780_mmc_softc *); +static void jz4780_mmc_intr(void *); +static int jz4780_mmc_enable_clock(struct jz4780_mmc_softc *); +static int jz4780_mmc_config_clock(struct jz4780_mmc_softc *, uint32_t); + +static int jz4780_mmc_update_ios(device_t, device_t); +static int jz4780_mmc_request(device_t, device_t, struct mmc_request *); +static int jz4780_mmc_get_ro(device_t, device_t); +static int jz4780_mmc_acquire_host(device_t, device_t); +static int jz4780_mmc_release_host(device_t, device_t); + +#define JZ_MMC_LOCK(_sc) mtx_lock(&(_sc)->sc_mtx) +#define JZ_MMC_UNLOCK(_sc) mtx_unlock(&(_sc)->sc_mtx) +#define JZ_MMC_READ_2(_sc, _reg) \ + bus_space_read_2((_sc)->sc_bst, (_sc)->sc_bsh, _reg) +#define JZ_MMC_WRITE_2(_sc, _reg, _value) \ + bus_space_write_2((_sc)->sc_bst, (_sc)->sc_bsh, _reg, _value) +#define JZ_MMC_READ_4(_sc, _reg) \ + bus_space_read_4((_sc)->sc_bst, (_sc)->sc_bsh, _reg) +#define JZ_MMC_WRITE_4(_sc, _reg, _value) \ + bus_space_write_4((_sc)->sc_bst, (_sc)->sc_bsh, _reg, _value) + +static int +jz4780_mmc_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-mmc")) + return (ENXIO); + if (device_get_unit(dev) > 0) /* XXXKAN */ + return (ENXIO); + device_set_desc(dev, "Ingenic JZ4780 Integrated MMC/SD controller"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jz4780_mmc_attach(device_t dev) +{ + struct jz4780_mmc_softc *sc; + struct sysctl_ctx_list *ctx; + struct sysctl_oid_list *tree; + device_t child; + ssize_t len; + pcell_t prop; + phandle_t node; + + sc = device_get_softc(dev); + sc->sc_dev = dev; + sc->sc_req = NULL; + if (bus_alloc_resources(dev, jz4780_mmc_res_spec, sc->sc_res) != 0) { + device_printf(dev, "cannot allocate device resources\n"); + return (ENXIO); + } + sc->sc_bst = rman_get_bustag(sc->sc_res[JZ_MSC_MEMRES]); + sc->sc_bsh = rman_get_bushandle(sc->sc_res[JZ_MSC_MEMRES]); + if (bus_setup_intr(dev, sc->sc_res[JZ_MSC_IRQRES], + INTR_TYPE_MISC | INTR_MPSAFE, NULL, jz4780_mmc_intr, sc, + &sc->sc_intrhand)) { + bus_release_resources(dev, jz4780_mmc_res_spec, sc->sc_res); + device_printf(dev, "cannot setup interrupt handler\n"); + return (ENXIO); + } + sc->sc_timeout = 10; + ctx = device_get_sysctl_ctx(dev); + tree = SYSCTL_CHILDREN(device_get_sysctl_tree(dev)); + SYSCTL_ADD_INT(ctx, tree, OID_AUTO, "req_timeout", CTLFLAG_RW, + &sc->sc_timeout, 0, "Request timeout in seconds"); + mtx_init(&sc->sc_mtx, device_get_nameunit(sc->sc_dev), "jz4780_mmc", + MTX_DEF); + callout_init_mtx(&sc->sc_timeoutc, &sc->sc_mtx, 0); + + /* Reset controller. */ + if (jz4780_mmc_reset(sc) != 0) { + device_printf(dev, "cannot reset the controller\n"); + goto fail; + } + if (jz4780_mmc_pio_mode == 0 && jz4780_mmc_setup_dma(sc) != 0) { + device_printf(sc->sc_dev, "Couldn't setup DMA!\n"); + jz4780_mmc_pio_mode = 1; + } + if (bootverbose) + device_printf(sc->sc_dev, "DMA status: %s\n", + jz4780_mmc_pio_mode ? "disabled" : "enabled"); + + node = ofw_bus_get_node(dev); + /* Determine max operating frequency */ + sc->sc_host.f_max = 24000000; + len = OF_getencprop(node, "max-frequency", &prop, sizeof(prop)); + if (len / sizeof(prop) == 1) + sc->sc_host.f_max = prop; + sc->sc_host.f_min = sc->sc_host.f_max / 128; + + sc->sc_host.host_ocr = MMC_OCR_320_330 | MMC_OCR_330_340; + sc->sc_host.caps = MMC_CAP_HSPEED; + sc->sc_host.mode = mode_sd; + /* + * Check for bus-width property, default to both 4 and 8 bit + * if no bus width is specified. + */ + len = OF_getencprop(node, "bus-width", &prop, sizeof(prop)); + if (len / sizeof(prop) != 1) + sc->sc_host.caps |= MMC_CAP_4_BIT_DATA | MMC_CAP_8_BIT_DATA; + else if (prop == 8) + sc->sc_host.caps |= MMC_CAP_8_BIT_DATA; + else if (prop == 4) + sc->sc_host.caps |= MMC_CAP_4_BIT_DATA; + /* Activate the module clock. */ + if (jz4780_mmc_enable_clock(sc) != 0) { + device_printf(dev, "cannot activate mmc clock\n"); + goto fail; + } + + child = device_add_child(dev, "mmc", -1); + if (child == NULL) { + device_printf(dev, "attaching MMC bus failed!\n"); + goto fail; + } + if (device_probe_and_attach(child) != 0) { + device_printf(dev, "attaching MMC child failed!\n"); + device_delete_child(dev, child); + goto fail; + } + + return (0); + +fail: + callout_drain(&sc->sc_timeoutc); + mtx_destroy(&sc->sc_mtx); + bus_teardown_intr(dev, sc->sc_res[JZ_MSC_IRQRES], sc->sc_intrhand); + bus_release_resources(dev, jz4780_mmc_res_spec, sc->sc_res); + if (sc->sc_clk != NULL) + clk_release(sc->sc_clk); + return (ENXIO); +} + +static int +jz4780_mmc_detach(device_t dev) +{ + + return (EBUSY); +} + +static int +jz4780_mmc_enable_clock(struct jz4780_mmc_softc *sc) +{ + int err; + + err = clk_get_by_ofw_name(sc->sc_dev, 0, "mmc", &sc->sc_clk); + if (err == 0) + err = clk_enable(sc->sc_clk); + if (err == 0) + err = clk_set_freq(sc->sc_clk, sc->sc_host.f_max, 0); + if (err != 0) + clk_release(sc->sc_clk); + return (err); +} + +static void +jz4780_mmc_dma_desc_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err) +{ + struct jz4780_mmc_softc *sc; + + sc = (struct jz4780_mmc_softc *)arg; + if (err) { + sc->sc_dma_map_err = err; + return; + } + sc->sc_dma_desc_phys = segs[0].ds_addr; +} + +static int +jz4780_mmc_setup_dma(struct jz4780_mmc_softc *sc) +{ + int dma_desc_size, error; + + /* Allocate the DMA descriptor memory. */ + dma_desc_size = sizeof(struct jz4780_mmc_dma_desc) * JZ_MSC_DMA_SEGS; + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + dma_desc_size, 1, dma_desc_size, 0, NULL, NULL, &sc->sc_dma_tag); + if (error) + return (error); + error = bus_dmamem_alloc(sc->sc_dma_tag, &sc->sc_dma_desc, + BUS_DMA_WAITOK | BUS_DMA_ZERO, &sc->sc_dma_map); + if (error) + return (error); + + error = bus_dmamap_load(sc->sc_dma_tag, sc->sc_dma_map, + sc->sc_dma_desc, dma_desc_size, jz4780_mmc_dma_desc_cb, sc, 0); + if (error) + return (error); + if (sc->sc_dma_map_err) + return (sc->sc_dma_map_err); + + /* Create the DMA map for data transfers. */ + error = bus_dma_tag_create(bus_get_dma_tag(sc->sc_dev), 1, 0, + BUS_SPACE_MAXADDR_32BIT, BUS_SPACE_MAXADDR, NULL, NULL, + JZ_MSC_DMA_MAX_SIZE * JZ_MSC_DMA_SEGS, JZ_MSC_DMA_SEGS, + JZ_MSC_DMA_MAX_SIZE, BUS_DMA_ALLOCNOW, NULL, NULL, + &sc->sc_dma_buf_tag); + if (error) + return (error); + error = bus_dmamap_create(sc->sc_dma_buf_tag, 0, + &sc->sc_dma_buf_map); + if (error) + return (error); + + return (0); +} + +static void +jz4780_mmc_dma_cb(void *arg, bus_dma_segment_t *segs, int nsegs, int err) +{ + struct jz4780_mmc_dma_desc *dma_desc; + struct jz4780_mmc_softc *sc; + uint32_t dma_desc_phys; + int i; + + sc = (struct jz4780_mmc_softc *)arg; + sc->sc_dma_map_err = err; + dma_desc = sc->sc_dma_desc; + dma_desc_phys = sc->sc_dma_desc_phys; + + /* Note nsegs is guaranteed to be zero if err is non-zero. */ + for (i = 0; i < nsegs; i++) { + dma_desc[i].dma_phys = segs[i].ds_addr; + dma_desc[i].dma_len = segs[i].ds_len; + if (i < (nsegs - 1)) { + dma_desc_phys += sizeof(struct jz4780_mmc_dma_desc); + dma_desc[i].dma_next = dma_desc_phys; + dma_desc[i].dma_cmd = (i << 16) | JZ_DMA_LINK; + } else { + dma_desc[i].dma_next = 0; + dma_desc[i].dma_cmd = (i << 16) | JZ_DMA_ENDI; + } +#ifdef JZ_MMC_DEBUG + device_printf(sc->sc_dev, "%d: desc %#x phys %#x len %d next %#x cmd %#x\n", + i, dma_desc_phys - sizeof(struct jz4780_mmc_dma_desc), + dma_desc[i].dma_phys, dma_desc[i].dma_len, + dma_desc[i].dma_next, dma_desc[i].dma_cmd); +#endif + } +} + +static int +jz4780_mmc_prepare_dma(struct jz4780_mmc_softc *sc) +{ + bus_dmasync_op_t sync_op; + int error; + struct mmc_command *cmd; + uint32_t off; + + cmd = sc->sc_req->cmd; + if (cmd->data->len > JZ_MSC_DMA_MAX_SIZE * JZ_MSC_DMA_SEGS) + return (EFBIG); + error = bus_dmamap_load(sc->sc_dma_buf_tag, sc->sc_dma_buf_map, + cmd->data->data, cmd->data->len, jz4780_mmc_dma_cb, sc, + BUS_DMA_NOWAIT); + if (error) + return (error); + if (sc->sc_dma_map_err) + return (sc->sc_dma_map_err); + + sc->sc_dma_inuse = 1; + if (cmd->data->flags & MMC_DATA_WRITE) + sync_op = BUS_DMASYNC_PREWRITE; + else + sync_op = BUS_DMASYNC_PREREAD; + bus_dmamap_sync(sc->sc_dma_buf_tag, sc->sc_dma_buf_map, sync_op); + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, BUS_DMASYNC_PREWRITE); + + /* Configure default DMA parameters */ + sc->sc_dma_ctl = JZ_MODE_SEL | JZ_INCR_64 | JZ_DMAEN; + + /* Enable unaligned buffer handling */ + off = (uintptr_t)cmd->data->data & 3; + if (off != 0) + sc->sc_dma_ctl |= (off << JZ_AOFST_S) | JZ_ALIGNEN; + return (0); +} + +static void +jz4780_mmc_start_dma(struct jz4780_mmc_softc *sc) +{ + + /* Set the address of the first descriptor */ + JZ_MMC_WRITE_4(sc, JZ_MSC_DMANDA, sc->sc_dma_desc_phys); + /* Enable and start the dma engine */ + JZ_MMC_WRITE_4(sc, JZ_MSC_DMAC, sc->sc_dma_ctl); +} + +static int +jz4780_mmc_reset(struct jz4780_mmc_softc *sc) +{ + int timeout; + int reg; + + /* Stop the clock */ + reg = JZ_MMC_READ_4(sc, JZ_MSC_CTRL); + reg &= ~(JZ_CLOCK_CTRL_M); + reg |= JZ_CLOCK_STOP; + JZ_MMC_WRITE_4(sc, JZ_MSC_CTRL, reg); + + timeout = 1000; + while (--timeout > 0) { + if ((JZ_MMC_READ_4(sc, JZ_MSC_STAT) & JZ_CLK_EN) == 0) + break; + DELAY(100); + } + if (timeout == 0) { + device_printf(sc->sc_dev, "Failed to stop clk.\n"); + return (ETIMEDOUT); + } + + /* Reset */ + reg = JZ_MMC_READ_4(sc, JZ_MSC_CTRL); + reg |= JZ_RESET; + JZ_MMC_WRITE_4(sc, JZ_MSC_CTRL, reg); + + timeout = 10; + while (--timeout > 0) { + if ((JZ_MMC_READ_4(sc, JZ_MSC_STAT) & JZ_IS_RESETTING) == 0) + break; + DELAY(1000); + } + + if (timeout == 0) { + /* + * X1000 never clears reseting bit. + * Ignore for now. + */ + } + + /* Set the timeouts. */ + JZ_MMC_WRITE_4(sc, JZ_MSC_RESTO, 0xffff); + JZ_MMC_WRITE_4(sc, JZ_MSC_RDTO, 0xffffffff); + + /* Mask all interrupt initially */ + JZ_MMC_WRITE_4(sc, JZ_MSC_IMASK, 0xffffffff); + /* Clear pending interrupts. */ + JZ_MMC_WRITE_4(sc, JZ_MSC_IFLG, 0xffffffff); + + /* Remember interrupts we always want */ + sc->sc_intr_mask = JZ_MSC_INT_ERR_BITS; + + return (0); +} + +static void +jz4780_mmc_req_done(struct jz4780_mmc_softc *sc) +{ + struct mmc_command *cmd; + struct mmc_request *req; + bus_dmasync_op_t sync_op; + + cmd = sc->sc_req->cmd; + /* Reset the controller in case of errors */ + if (cmd->error != MMC_ERR_NONE) + jz4780_mmc_reset(sc); + /* Unmap DMA if necessary */ + if (sc->sc_dma_inuse == 1) { + if (cmd->data->flags & MMC_DATA_WRITE) + sync_op = BUS_DMASYNC_POSTWRITE; + else + sync_op = BUS_DMASYNC_POSTREAD; + bus_dmamap_sync(sc->sc_dma_buf_tag, sc->sc_dma_buf_map, + sync_op); + bus_dmamap_sync(sc->sc_dma_tag, sc->sc_dma_map, + BUS_DMASYNC_POSTWRITE); + bus_dmamap_unload(sc->sc_dma_buf_tag, sc->sc_dma_buf_map); + } + req = sc->sc_req; + callout_stop(&sc->sc_timeoutc); + sc->sc_req = NULL; + sc->sc_resid = 0; + sc->sc_dma_inuse = 0; + sc->sc_dma_map_err = 0; + sc->sc_intr_wait = 0; + sc->sc_intr_seen = 0; + req->done(req); +} + +static void +jz4780_mmc_read_response(struct jz4780_mmc_softc *sc) +{ + struct mmc_command *cmd; + int i; + + cmd = sc->sc_req->cmd; + if (cmd->flags & MMC_RSP_PRESENT) { + if (cmd->flags & MMC_RSP_136) { + uint16_t val; + + val = JZ_MMC_READ_2(sc, JZ_MSC_RES); + for (i = 0; i < 4; i++) { + cmd->resp[i] = val << 24; + val = JZ_MMC_READ_2(sc, JZ_MSC_RES); + cmd->resp[i] |= val << 8; + val = JZ_MMC_READ_2(sc, JZ_MSC_RES); + cmd->resp[i] |= val >> 8; + } + } else { + cmd->resp[0] = JZ_MMC_READ_2(sc, JZ_MSC_RES) << 24; + cmd->resp[0] |= JZ_MMC_READ_2(sc, JZ_MSC_RES) << 8; + cmd->resp[0] |= JZ_MMC_READ_2(sc, JZ_MSC_RES) & 0xff; + } + } +} + +static void +jz4780_mmc_req_ok(struct jz4780_mmc_softc *sc) +{ + struct mmc_command *cmd; + + cmd = sc->sc_req->cmd; + /* All data has been transferred ? */ + if (cmd->data != NULL && (sc->sc_resid << 2) < cmd->data->len) + cmd->error = MMC_ERR_FAILED; + jz4780_mmc_req_done(sc); +} + +static void +jz4780_mmc_timeout(void *arg) +{ + struct jz4780_mmc_softc *sc; + + sc = (struct jz4780_mmc_softc *)arg; + if (sc->sc_req != NULL) { + device_printf(sc->sc_dev, "controller timeout, rint %#x stat %#x\n", + JZ_MMC_READ_4(sc, JZ_MSC_IFLG), JZ_MMC_READ_4(sc, JZ_MSC_STAT)); + sc->sc_req->cmd->error = MMC_ERR_TIMEOUT; + jz4780_mmc_req_done(sc); + } else + device_printf(sc->sc_dev, + "Spurious timeout - no active request\n"); +} + +static int +jz4780_mmc_pio_transfer(struct jz4780_mmc_softc *sc, struct mmc_data *data) +{ + uint32_t mask, *buf; + int i, write; + + buf = (uint32_t *)data->data; + write = (data->flags & MMC_DATA_WRITE) ? 1 : 0; + mask = write ? JZ_DATA_FIFO_FULL : JZ_DATA_FIFO_EMPTY; + for (i = sc->sc_resid; i < (data->len >> 2); i++) { + if ((JZ_MMC_READ_4(sc, JZ_MSC_STAT) & mask)) + return (1); + if (write) + JZ_MMC_WRITE_4(sc, JZ_MSC_TXFIFO, buf[i]); + else + buf[i] = JZ_MMC_READ_4(sc, JZ_MSC_RXFIFO); + sc->sc_resid = i + 1; + } + + /* Done with pio transfer, shut FIFO interrupts down */ + mask = JZ_MMC_READ_4(sc, JZ_MSC_IMASK); + mask |= (JZ_INT_TXFIFO_WR_REQ | JZ_INT_RXFIFO_RD_REQ); + JZ_MMC_WRITE_4(sc, JZ_MSC_IMASK, mask); + return (0); +} + +static void +jz4780_mmc_intr(void *arg) +{ + struct jz4780_mmc_softc *sc; + struct mmc_data *data; + uint32_t rint; + + sc = (struct jz4780_mmc_softc *)arg; + JZ_MMC_LOCK(sc); + rint = JZ_MMC_READ_4(sc, JZ_MSC_IFLG); +#if defined(JZ_MMC_DEBUG) + device_printf(sc->sc_dev, "rint: %#x, stat: %#x\n", + rint, JZ_MMC_READ_4(sc, JZ_MSC_STAT)); + if (sc->sc_dma_inuse == 1 && (sc->sc_intr_seen & JZ_INT_DMAEND) == 0) + device_printf(sc->sc_dev, "\tdmada %#x dmanext %#x dmac %#x" + " dmalen %d dmacmd %#x\n", + JZ_MMC_READ_4(sc, JZ_MSC_DMADA), + JZ_MMC_READ_4(sc, JZ_MSC_DMANDA), + JZ_MMC_READ_4(sc, JZ_MSC_DMAC), + JZ_MMC_READ_4(sc, JZ_MSC_DMALEN), + JZ_MMC_READ_4(sc, JZ_MSC_DMACMD)); +#endif + if (sc->sc_req == NULL) { + device_printf(sc->sc_dev, + "Spurious interrupt - no active request, rint: 0x%08X\n", + rint); + goto end; + } + if (rint & JZ_MSC_INT_ERR_BITS) { +#if defined(JZ_MMC_DEBUG) + device_printf(sc->sc_dev, "controller error, rint %#x stat %#x\n", + rint, JZ_MMC_READ_4(sc, JZ_MSC_STAT)); +#endif + if (rint & (JZ_INT_TIMEOUT_RES | JZ_INT_TIMEOUT_READ)) + sc->sc_req->cmd->error = MMC_ERR_TIMEOUT; + else + sc->sc_req->cmd->error = MMC_ERR_FAILED; + jz4780_mmc_req_done(sc); + goto end; + } + data = sc->sc_req->cmd->data; + /* Check for command response */ + if (rint & JZ_INT_END_CMD_RES) { + jz4780_mmc_read_response(sc); + if (sc->sc_dma_inuse == 1) + jz4780_mmc_start_dma(sc); + } + if (data != NULL) { + if (sc->sc_dma_inuse == 1 && (rint & JZ_INT_DMAEND)) + sc->sc_resid = data->len >> 2; + else if (sc->sc_dma_inuse == 0 && + (rint & (JZ_INT_TXFIFO_WR_REQ | JZ_INT_RXFIFO_RD_REQ))) + jz4780_mmc_pio_transfer(sc, data); + } + sc->sc_intr_seen |= rint; + if ((sc->sc_intr_seen & sc->sc_intr_wait) == sc->sc_intr_wait) + jz4780_mmc_req_ok(sc); +end: + JZ_MMC_WRITE_4(sc, JZ_MSC_IFLG, rint); + JZ_MMC_UNLOCK(sc); +} + +static int +jz4780_mmc_request(device_t bus, device_t child, struct mmc_request *req) +{ + struct jz4780_mmc_softc *sc; + struct mmc_command *cmd; + uint32_t cmdat, ctrl, iwait; + int blksz; + + sc = device_get_softc(bus); + JZ_MMC_LOCK(sc); + if (sc->sc_req != NULL) { + JZ_MMC_UNLOCK(sc); + return (EBUSY); + } + /* Start with template value */ + cmdat = sc->sc_cmdat; + iwait = JZ_INT_END_CMD_RES; + + /* Configure response format */ + cmd = req->cmd; + switch (MMC_RSP(cmd->flags)) { + case MMC_RSP_R1: + case MMC_RSP_R1B: + cmdat |= JZ_RES_R1; + break; + case MMC_RSP_R2: + cmdat |= JZ_RES_R2; + break; + case MMC_RSP_R3: + cmdat |= JZ_RES_R3; + break; + }; + if (cmd->opcode == MMC_GO_IDLE_STATE) + cmdat |= JZ_INIT; + if (cmd->flags & MMC_RSP_BUSY) { + cmdat |= JZ_BUSY; + iwait |= JZ_INT_PRG_DONE; + } + + sc->sc_req = req; + sc->sc_resid = 0; + cmd->error = MMC_ERR_NONE; + + if (cmd->data != NULL) { + cmdat |= JZ_DATA_EN; + if (cmd->data->flags & MMC_DATA_MULTI) { + cmdat |= JZ_AUTO_CMD12; + iwait |= JZ_INT_AUTO_CMD12_DONE; + } + if (cmd->data->flags & MMC_DATA_WRITE) { + cmdat |= JZ_WRITE; + iwait |= JZ_INT_PRG_DONE; + } + if (cmd->data->flags & MMC_DATA_STREAM) + cmdat |= JZ_STREAM; + else + iwait |= JZ_INT_DATA_TRAN_DONE; + + blksz = min(cmd->data->len, MMC_SECTOR_SIZE); + JZ_MMC_WRITE_4(sc, JZ_MSC_BLKLEN, blksz); + JZ_MMC_WRITE_4(sc, JZ_MSC_NOB, cmd->data->len / blksz); + + /* Attempt to setup DMA for this transaction */ + if (jz4780_mmc_pio_mode == 0) + jz4780_mmc_prepare_dma(sc); + if (sc->sc_dma_inuse != 0) { + /* Wait for DMA completion interrupt */ + iwait |= JZ_INT_DMAEND; + } else { + iwait |= (cmd->data->flags & MMC_DATA_WRITE) ? + JZ_INT_TXFIFO_WR_REQ : JZ_INT_RXFIFO_RD_REQ; + JZ_MMC_WRITE_4(sc, JZ_MSC_DMAC, 0); + } + } + + sc->sc_intr_seen = 0; + sc->sc_intr_wait = iwait; + JZ_MMC_WRITE_4(sc, JZ_MSC_IMASK, ~(sc->sc_intr_mask | iwait)); + +#if defined(JZ_MMC_DEBUG) + device_printf(sc->sc_dev, + "REQUEST: CMD%u arg %#x flags %#x cmdat %#x sc_intr_wait = %#x\n", + cmd->opcode, cmd->arg, cmd->flags, cmdat, sc->sc_intr_wait); +#endif + + JZ_MMC_WRITE_4(sc, JZ_MSC_ARG, cmd->arg); + JZ_MMC_WRITE_4(sc, JZ_MSC_CMD, cmd->opcode); + JZ_MMC_WRITE_4(sc, JZ_MSC_CMDAT, cmdat); + + ctrl = JZ_MMC_READ_4(sc, JZ_MSC_CTRL); + ctrl |= JZ_START_OP | JZ_CLOCK_START; + JZ_MMC_WRITE_4(sc, JZ_MSC_CTRL, ctrl); + + callout_reset(&sc->sc_timeoutc, sc->sc_timeout * hz, + jz4780_mmc_timeout, sc); + JZ_MMC_UNLOCK(sc); + + return (0); +} + +static int +jz4780_mmc_read_ivar(device_t bus, device_t child, int which, + uintptr_t *result) +{ + struct jz4780_mmc_softc *sc; + + sc = device_get_softc(bus); + switch (which) { + default: + return (EINVAL); + case MMCBR_IVAR_BUS_MODE: + *(int *)result = sc->sc_host.ios.bus_mode; + break; + case MMCBR_IVAR_BUS_WIDTH: + *(int *)result = sc->sc_host.ios.bus_width; + break; + case MMCBR_IVAR_CHIP_SELECT: + *(int *)result = sc->sc_host.ios.chip_select; + break; + case MMCBR_IVAR_CLOCK: + *(int *)result = sc->sc_host.ios.clock; + break; + case MMCBR_IVAR_F_MIN: + *(int *)result = sc->sc_host.f_min; + break; + case MMCBR_IVAR_F_MAX: + *(int *)result = sc->sc_host.f_max; + break; + case MMCBR_IVAR_HOST_OCR: + *(int *)result = sc->sc_host.host_ocr; + break; + case MMCBR_IVAR_MODE: + *(int *)result = sc->sc_host.mode; + break; + case MMCBR_IVAR_OCR: + *(int *)result = sc->sc_host.ocr; + break; + case MMCBR_IVAR_POWER_MODE: + *(int *)result = sc->sc_host.ios.power_mode; + break; + case MMCBR_IVAR_VDD: + *(int *)result = sc->sc_host.ios.vdd; + break; + case MMCBR_IVAR_CAPS: + *(int *)result = sc->sc_host.caps; + break; + case MMCBR_IVAR_MAX_DATA: + *(int *)result = 65535; + break; + case MMCBR_IVAR_TIMING: + *(int *)result = sc->sc_host.ios.timing; + break; + } + + return (0); +} + +static int +jz4780_mmc_write_ivar(device_t bus, device_t child, int which, + uintptr_t value) +{ + struct jz4780_mmc_softc *sc; + + sc = device_get_softc(bus); + switch (which) { + default: + return (EINVAL); + case MMCBR_IVAR_BUS_MODE: + sc->sc_host.ios.bus_mode = value; + break; + case MMCBR_IVAR_BUS_WIDTH: + sc->sc_host.ios.bus_width = value; + break; + case MMCBR_IVAR_CHIP_SELECT: + sc->sc_host.ios.chip_select = value; + break; + case MMCBR_IVAR_CLOCK: + sc->sc_host.ios.clock = value; + break; + case MMCBR_IVAR_MODE: + sc->sc_host.mode = value; + break; + case MMCBR_IVAR_OCR: + sc->sc_host.ocr = value; + break; + case MMCBR_IVAR_POWER_MODE: + sc->sc_host.ios.power_mode = value; + break; + case MMCBR_IVAR_VDD: + sc->sc_host.ios.vdd = value; + break; + case MMCBR_IVAR_TIMING: + sc->sc_host.ios.timing = value; + break; + /* These are read-only */ + case MMCBR_IVAR_CAPS: + case MMCBR_IVAR_HOST_OCR: + case MMCBR_IVAR_F_MIN: + case MMCBR_IVAR_F_MAX: + case MMCBR_IVAR_MAX_DATA: + return (EINVAL); + } + + return (0); +} + +static int +jz4780_mmc_disable_clock(struct jz4780_mmc_softc *sc) +{ + int timeout; + + JZ_MMC_WRITE_4(sc, JZ_MSC_CTRL, + JZ_MMC_READ_4(sc, JZ_MSC_CTRL) | JZ_CLOCK_STOP); + + for (timeout = 1000; timeout > 0; timeout--) + if ((JZ_MMC_READ_4(sc, JZ_MSC_STAT) & JZ_CLK_EN) == 0) + return (0); + return (ETIMEDOUT); +} + +static int +jz4780_mmc_config_clock(struct jz4780_mmc_softc *sc, uint32_t freq) +{ + uint64_t rate; + uint32_t clk_freq; + int err, div; + + err = jz4780_mmc_disable_clock(sc); + if (err != 0) + return (err); + + clk_get_freq(sc->sc_clk, &rate); + clk_freq = (uint32_t)rate; + + div = 0; + while (clk_freq > freq) { + div++; + clk_freq >>= 1; + } + if (div >= 7) + div = 7; +#if defined(JZ_MMC_DEBUG) + if (div != JZ_MMC_READ_4(sc, JZ_MSC_CLKRT)) + device_printf(sc->sc_dev, + "UPDATE_IOS: clk -> %u\n", clk_freq); +#endif + JZ_MMC_WRITE_4(sc, JZ_MSC_CLKRT, div); + return (0); +} + +static int +jz4780_mmc_update_ios(device_t bus, device_t child) +{ + struct jz4780_mmc_softc *sc; + struct mmc_ios *ios; + int error; + + sc = device_get_softc(bus); + ios = &sc->sc_host.ios; + if (ios->clock) { + /* Set the MMC clock. */ + error = jz4780_mmc_config_clock(sc, ios->clock); + if (error != 0) + return (error); + } + + /* Set the bus width. */ + switch (ios->bus_width) { + case bus_width_1: + sc->sc_cmdat &= ~(JZ_BUS_WIDTH_M); + sc->sc_cmdat |= JZ_BUS_1BIT; + break; + case bus_width_4: + sc->sc_cmdat &= ~(JZ_BUS_WIDTH_M); + sc->sc_cmdat |= JZ_BUS_4BIT; + break; + case bus_width_8: + sc->sc_cmdat &= ~(JZ_BUS_WIDTH_M); + sc->sc_cmdat |= JZ_BUS_8BIT; + break; + } + return (0); +} + +static int +jz4780_mmc_get_ro(device_t bus, device_t child) +{ + + return (0); +} + +static int +jz4780_mmc_acquire_host(device_t bus, device_t child) +{ + struct jz4780_mmc_softc *sc; + int error; + + sc = device_get_softc(bus); + JZ_MMC_LOCK(sc); + while (sc->sc_bus_busy) { + error = msleep(sc, &sc->sc_mtx, PCATCH, "mmchw", 0); + if (error != 0) { + JZ_MMC_UNLOCK(sc); + return (error); + } + } + sc->sc_bus_busy++; + JZ_MMC_UNLOCK(sc); + + return (0); +} + +static int +jz4780_mmc_release_host(device_t bus, device_t child) +{ + struct jz4780_mmc_softc *sc; + + sc = device_get_softc(bus); + JZ_MMC_LOCK(sc); + sc->sc_bus_busy--; + wakeup(sc); + JZ_MMC_UNLOCK(sc); + + return (0); +} + +static device_method_t jz4780_mmc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_mmc_probe), + DEVMETHOD(device_attach, jz4780_mmc_attach), + DEVMETHOD(device_detach, jz4780_mmc_detach), + + /* Bus interface */ + DEVMETHOD(bus_read_ivar, jz4780_mmc_read_ivar), + DEVMETHOD(bus_write_ivar, jz4780_mmc_write_ivar), + DEVMETHOD(bus_print_child, bus_generic_print_child), + + /* MMC bridge interface */ + DEVMETHOD(mmcbr_update_ios, jz4780_mmc_update_ios), + DEVMETHOD(mmcbr_request, jz4780_mmc_request), + DEVMETHOD(mmcbr_get_ro, jz4780_mmc_get_ro), + DEVMETHOD(mmcbr_acquire_host, jz4780_mmc_acquire_host), + DEVMETHOD(mmcbr_release_host, jz4780_mmc_release_host), + + DEVMETHOD_END +}; + +static devclass_t jz4780_mmc_devclass; + +static driver_t jz4780_mmc_driver = { + "jzmmc", + jz4780_mmc_methods, + sizeof(struct jz4780_mmc_softc), +}; + +DRIVER_MODULE(jzmmc, simplebus, jz4780_mmc_driver, jz4780_mmc_devclass, 0, 0); +DRIVER_MODULE(mmc, jzmmc, mmc_driver, mmc_devclass, NULL, NULL); +MODULE_DEPEND(jzmmc, mmc, 1, 1, 1); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_mmc.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_mp.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_mp.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_mp.c (revision 308868) @@ -0,0 +1,182 @@ +/*- + * Copyright (c) 2015 Alexander Kabaev + * Copyright (c) 2004-2010 Juli Mallett + * 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. + * + * $FreeBSD$ + */ +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +void jz4780_mpentry(void); + +#define JZ4780_MAXCPU 2 + +void +platform_ipi_send(int cpuid) +{ + + if (cpuid == 0) + mips_wr_xburst_mbox0(1); + else + mips_wr_xburst_mbox1(1); +} + +void +platform_ipi_clear(void) +{ + int cpuid = PCPU_GET(cpuid); + uint32_t action; + + action = (cpuid == 0) ? mips_rd_xburst_mbox0() : mips_rd_xburst_mbox1(); + KASSERT(action == 1, ("CPU %d: unexpected IPIs: %#x", cpuid, action)); + mips_wr_xburst_core_sts(~(JZ_CORESTS_MIRQ0P << cpuid)); +} + +int +platform_processor_id(void) +{ + + return (mips_rd_ebase() & 7); +} + +int +platform_ipi_hardintr_num(void) +{ + + return (1); +} + +int +platform_ipi_softintr_num(void) +{ + + return (-1); +} + +void +platform_init_ap(int cpuid) +{ + unsigned reg; + + /* + * Clear any pending IPIs. + */ + mips_wr_xburst_core_sts(~(JZ_CORESTS_MIRQ0P << cpuid)); + + /* Allow IPI mbox for this core */ + reg = mips_rd_xburst_reim(); + reg |= (JZ_REIM_MIRQ0M << cpuid); + mips_wr_xburst_reim(reg); + + /* + * Unmask the ipi interrupts. + */ + reg = hard_int_mask(platform_ipi_hardintr_num()); + set_intr_mask(reg); +} + +void +platform_cpu_mask(cpuset_t *mask) +{ + uint32_t i, m; + + CPU_ZERO(mask); + for (i = 0, m = 1 ; i < JZ4780_MAXCPU; i++, m <<= 1) + CPU_SET(i, mask); +} + +struct cpu_group * +platform_smp_topo(void) +{ + return (smp_topo_none()); +} + +static void +jz4780_core_powerup(void) +{ + uint32_t reg; + + reg = readreg(JZ_CGU_BASE + JZ_LPCR); + reg &= ~LPCR_PD_SCPU; + writereg(JZ_CGU_BASE + JZ_LPCR, reg); + do { + reg = readreg(JZ_CGU_BASE + JZ_LPCR); + } while ((reg & LPCR_SCPUS) != 0); +} + +/* + * Spin up the second code. The code is roughly modeled after + * similar routine in Linux. + */ +int +platform_start_ap(int cpuid) +{ + uint32_t reg, addr; + + if (cpuid >= JZ4780_MAXCPU) + return (EINVAL); + + /* Figure out address of mpentry in KSEG1 */ + addr = MIPS_PHYS_TO_KSEG1(MIPS_KSEG0_TO_PHYS(jz4780_mpentry)); + KASSERT((addr & ~JZ_REIM_ENTRY_MASK) == 0, + ("Unaligned mpentry")); + + /* Configure core alternative entry point */ + reg = mips_rd_xburst_reim(); + reg &= ~JZ_REIM_ENTRY_MASK; + reg |= addr & JZ_REIM_ENTRY_MASK; + + /* Allow this core to get IPIs from one being started */ + reg |= JZ_REIM_MIRQ0M; + mips_wr_xburst_reim(reg); + + /* Force core into reset and enable use of alternate entry point */ + reg = mips_rd_xburst_core_ctl(); + reg |= (JZ_CORECTL_SWRST0 << cpuid) | (JZ_CORECTL_RPC0 << cpuid); + mips_wr_xburst_core_ctl(reg); + + /* Power the core up */ + jz4780_core_powerup(); + + /* Take the core out of reset */ + reg &= ~(JZ_CORECTL_SWRST0 << cpuid); + mips_wr_xburst_core_ctl(reg); + + return (0); +} Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_mp.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_mpboot.S =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_mpboot.S (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_mpboot.S (revision 308868) @@ -0,0 +1,62 @@ +/*- + * Copyright (c) 2015 Alexander Kabaev + * 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. + * + * $FreeBSD$ + */ + +#include +#include +#include +#include + +#include "assym.s" + +#define CACHE_SIZE (32 * 1024) +#define CACHE_LINESIZE 32 + + .text + .set noat + .set noreorder + .section .text.mpentry_jz4780 + .balign 0x10000 + +GLOBAL(jz4780_mpentry) + + /* Initialize caches */ + li t0, MIPS_KSEG0_START + ori t1, t0, CACHE_SIZE + mtc0 zero, MIPS_COP_0_TAG_LO + COP0_SYNC +1: cache CACHEOP_R4K_INDEX_STORE_TAG | CACHE_R4K_I, 0(t0) + cache CACHEOP_R4K_INDEX_STORE_TAG | CACHE_R4K_D, 0(t0) + bne t0, t1, 1b + addiu t0, t0, CACHE_LINESIZE + + /* Set TLB page mask */ + mtc0 zero, MIPS_COP_0_TLB_PG_MASK + COP0_SYNC + + j mpentry + nop Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_mpboot.S ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_nand.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_nand.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_nand.c (revision 308868) @@ -0,0 +1,123 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + */ + +/* + * Ingenic JZ4780 NAND and External Memory Controller (NEMC) driver. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include +#include + +struct jz4780_nand_softc { + device_t dev; + struct resource *res[1]; +}; + +static struct resource_spec jz4780_nand_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +static int jz4780_nand_probe(device_t dev); +static int jz4780_nand_attach(device_t dev); +static int jz4780_nand_detach(device_t dev); + +static int +jz4780_nand_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-nand")) + return (ENXIO); + + device_set_desc(dev, "Ingenic JZ4780 NAND Controller"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jz4780_nand_attach(device_t dev) +{ + struct jz4780_nand_softc *sc = device_get_softc(dev); + + sc->dev = dev; + + if (bus_alloc_resources(dev, jz4780_nand_spec, sc->res)) { + device_printf(dev, "could not allocate resources for device\n"); + return (ENXIO); + } + + return (0); +} + +static int +jz4780_nand_detach(device_t dev) +{ + struct jz4780_nand_softc *sc = device_get_softc(dev); + + bus_release_resources(dev, jz4780_nand_spec, sc->res); + return (0); +} + +static device_method_t jz4780_nand_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_nand_probe), + DEVMETHOD(device_attach, jz4780_nand_attach), + DEVMETHOD(device_detach, jz4780_nand_detach), + + DEVMETHOD_END +}; + +static driver_t jz4780_nand_driver = { + "nand", + jz4780_nand_methods, + sizeof(struct jz4780_nand_softc), +}; + +static devclass_t jz4780_nand_devclass; + +DRIVER_MODULE(jz4780_nand, simplebus, jz4780_nand_driver, + jz4780_nand_devclass, 0, 0); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_nand.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_nemc.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_nemc.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_nemc.c (revision 308868) @@ -0,0 +1,373 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + */ + +/* + * Ingenic JZ4780 NAND and External Memory Controller (NEMC) driver. + * + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include + +#include +#include +#include +#include + +#include + +struct jz4780_nemc_devinfo { + struct simplebus_devinfo sinfo; + uint32_t bank; +}; + +struct jz4780_nemc_softc { + struct simplebus_softc simplebus_sc; + device_t dev; + struct resource *res[1]; + uint32_t banks; + uint32_t clock_tick_psecs; + clk_t clk; +}; + +static struct resource_spec jz4780_nemc_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { -1, 0 } +}; + +#define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], reg, (val)) +#define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], reg) + +static int jz4780_nemc_probe(device_t dev); +static int jz4780_nemc_attach(device_t dev); +static int jz4780_nemc_detach(device_t dev); + +static int +jz4780_nemc_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-nemc")) + return (ENXIO); + + device_set_desc(dev, "Ingenic JZ4780 NEMC"); + + return (BUS_PROBE_DEFAULT); +} + +#define JZ4780_NEMC_NS_TO_TICKS(sc, val) howmany((val) * 1000, (sc)->clock_tick_psecs) + +/* Use table from JZ4780 programmers manual to convert ticks to tBP/tAW register values */ +static const uint8_t ticks_to_tBP_tAW[32] = { + 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, /* 1:1 mapping */ + 11, 11, /* 12 cycles */ + 12, 12, 12, /* 15 cycles */ + 13, 13, 13, 13, 13, /* 20 cycles */ + 14, 14, 14, 14, 14, /* 25 cycles */ + 15, 15, 15, 15, 15, 15 /* 31 cycles */ +}; + +static int +jz4780_nemc_configure_bank(struct jz4780_nemc_softc *sc, + device_t dev, u_int bank) +{ + uint32_t smcr, cycles; + phandle_t node; + pcell_t val; + + /* Check if bank is configured already */ + if (sc->banks & (1 << bank)) + return 0; + + smcr = CSR_READ_4(sc, JZ_NEMC_SMCR(bank)); + + smcr &= ~JZ_NEMC_SMCR_SMT_MASK; + smcr |= JZ_NEMC_SMCR_SMT_NORMAL << JZ_NEMC_SMCR_SMT_SHIFT; + + node = ofw_bus_get_node(dev); + if (OF_getencprop(node, "ingenic,nemc-tAS", &val, sizeof(val)) > 0) { + cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val); + if (cycles > 15) { + device_printf(sc->dev, + "invalid value of %s %u (%u cycles), maximum %u cycles supported\n", + "ingenic,nemc-tAS", val, cycles, 15); + return -1; + } + smcr &= ~JZ_NEMC_SMCR_TAS_MASK; + smcr |= cycles << JZ_NEMC_SMCR_TAS_SHIFT; + } + + if (OF_getencprop(node, "ingenic,nemc-tAH", &val, sizeof(val)) > 0) { + cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val); + if (cycles > 15) { + device_printf(sc->dev, + "invalid value of %s %u (%u cycles), maximum %u cycles supported\n", + "ingenic,nemc-tAH", val, cycles, 15); + return -1; + } + smcr &= ~JZ_NEMC_SMCR_TAH_MASK; + smcr |= cycles << JZ_NEMC_SMCR_TAH_SHIFT; + } + + if (OF_getencprop(node, "ingenic,nemc-tBP", &val, sizeof(val)) > 0) { + cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val); + if (cycles > 31) { + device_printf(sc->dev, + "invalid value of %s %u (%u cycles), maximum %u cycles supported\n", + "ingenic,nemc-tBP", val, cycles, 15); + return -1; + } + smcr &= ~JZ_NEMC_SMCR_TBP_MASK; + smcr |= ticks_to_tBP_tAW[cycles] << JZ_NEMC_SMCR_TBP_SHIFT; + } + + if (OF_getencprop(node, "ingenic,nemc-tAW", &val, sizeof(val)) > 0) { + cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val); + if (cycles > 31) { + device_printf(sc->dev, + "invalid value of %s %u (%u cycles), maximum %u cycles supported\n", + "ingenic,nemc-tAW", val, cycles, 15); + return -1; + } + smcr &= ~JZ_NEMC_SMCR_TAW_MASK; + smcr |= ticks_to_tBP_tAW[cycles] << JZ_NEMC_SMCR_TAW_SHIFT; + } + + if (OF_getencprop(node, "ingenic,nemc-tSTRV", &val, sizeof(val)) > 0) { + cycles = JZ4780_NEMC_NS_TO_TICKS(sc, val); + if (cycles > 63) { + device_printf(sc->dev, + "invalid value of %s %u (%u cycles), maximum %u cycles supported\n", + "ingenic,nemc-tSTRV", val, cycles, 15); + return -1; + } + smcr &= ~JZ_NEMC_SMCR_STRV_MASK; + smcr |= cycles << JZ_NEMC_SMCR_STRV_SHIFT; + } + CSR_WRITE_4(sc, JZ_NEMC_SMCR(bank), smcr); + sc->banks |= (1 << bank); + return 0; +} + +/* Wholesale copy of simplebus routine */ +static int +jz4780_nemc_fill_ranges(phandle_t node, struct simplebus_softc *sc) +{ + int host_address_cells; + cell_t *base_ranges; + ssize_t nbase_ranges; + int err; + int i, j, k; + + err = OF_searchencprop(OF_parent(node), "#address-cells", + &host_address_cells, sizeof(host_address_cells)); + if (err <= 0) + return (-1); + + nbase_ranges = OF_getproplen(node, "ranges"); + if (nbase_ranges < 0) + return (-1); + sc->nranges = nbase_ranges / sizeof(cell_t) / + (sc->acells + host_address_cells + sc->scells); + if (sc->nranges == 0) + return (0); + + sc->ranges = malloc(sc->nranges * sizeof(sc->ranges[0]), + M_DEVBUF, M_WAITOK); + base_ranges = malloc(nbase_ranges, M_DEVBUF, M_WAITOK); + OF_getencprop(node, "ranges", base_ranges, nbase_ranges); + + for (i = 0, j = 0; i < sc->nranges; i++) { + sc->ranges[i].bus = 0; + for (k = 0; k < sc->acells; k++) { + sc->ranges[i].bus <<= 32; + sc->ranges[i].bus |= base_ranges[j++]; + } + sc->ranges[i].host = 0; + for (k = 0; k < host_address_cells; k++) { + sc->ranges[i].host <<= 32; + sc->ranges[i].host |= base_ranges[j++]; + } + sc->ranges[i].size = 0; + for (k = 0; k < sc->scells; k++) { + sc->ranges[i].size <<= 32; + sc->ranges[i].size |= base_ranges[j++]; + } + } + + free(base_ranges, M_DEVBUF); + return (sc->nranges); +} + +static int +jz4780_nemc_attach(device_t dev) +{ + struct jz4780_nemc_softc *sc = device_get_softc(dev); + phandle_t node; + uint64_t freq; + + sc->dev = dev; + + if (bus_alloc_resources(dev, jz4780_nemc_spec, sc->res)) { + device_printf(dev, "could not allocate resources for device\n"); + return (ENXIO); + } + + node = ofw_bus_get_node(dev); + + /* Initialize simplebus and enumerate resources */ + simplebus_init(dev, node); + + if (jz4780_nemc_fill_ranges(node, &sc->simplebus_sc) < 0) + goto error; + + /* Figure our underlying clock rate. */ + if (clk_get_by_ofw_index(dev, 0, 0, &sc->clk) != 0) { + device_printf(dev, "could not lookup device clock\n"); + goto error; + } + if (clk_enable(sc->clk) != 0) { + device_printf(dev, "could not enable device clock\n"); + goto error; + } + if (clk_get_freq(sc->clk, &freq) != 0) { + device_printf(dev, "could not determine clock speed\n"); + goto error; + } + + /* Convert clock frequency to picoseconds-per-tick value. */ + sc->clock_tick_psecs = (uint32_t)(1000000000000ULL / freq); + + /* + * Allow devices to identify. + */ + bus_generic_probe(dev); + + /* + * Now walk the tree and attach top level devices + */ + for (node = OF_child(node); node > 0; node = OF_peer(node)) + simplebus_add_device(dev, node, 0, NULL, -1, NULL); + + return (bus_generic_attach(dev)); +error: + jz4780_nemc_detach(dev); + return (ENXIO); +} + +static int +jz4780_nemc_detach(device_t dev) +{ + struct jz4780_nemc_softc *sc = device_get_softc(dev); + + bus_generic_detach(dev); + if (sc->clk != NULL) + clk_release(sc->clk); + bus_release_resources(dev, jz4780_nemc_spec, sc->res); + return (0); +} + +static int +jz4780_nemc_decode_bank(struct simplebus_softc *sc, struct resource *r, + u_int *bank) +{ + rman_res_t start, end; + int i; + + start = rman_get_start(r); + end = rman_get_end(r); + + /* Remap through ranges property */ + for (i = 0; i < sc->nranges; i++) { + if (start >= sc->ranges[i].host && end < + sc->ranges[i].host + sc->ranges[i].size) { + *bank = (sc->ranges[i].bus >> 32); + return (0); + } + } + return (1); +} + +static int +jz4780_nemc_activate_resource(device_t bus, device_t child, int type, int rid, + struct resource *r) +{ + struct jz4780_nemc_softc *sc; + u_int bank; + int err; + + if (type == SYS_RES_MEMORY) { + sc = device_get_softc(bus); + + /* Figure out on what bank device is residing */ + err = jz4780_nemc_decode_bank(&sc->simplebus_sc, r, &bank); + if (err == 0) { + /* Attempt to configure the bank if not done already */ + err = jz4780_nemc_configure_bank(sc, child, bank); + if (err != 0) + return (err); + } + } + + /* Call default implementation to finish the work */ + return (bus_generic_activate_resource(bus, child, + type, rid, r)); +} + +static device_method_t jz4780_nemc_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_nemc_probe), + DEVMETHOD(device_attach, jz4780_nemc_attach), + DEVMETHOD(device_detach, jz4780_nemc_detach), + + /* Overrides to configure bank on resource activation */ + DEVMETHOD(bus_activate_resource, jz4780_nemc_activate_resource), + + DEVMETHOD_END +}; + +static devclass_t jz4780_nemc_devclass; +DEFINE_CLASS_1(nemc, jz4780_nemc_driver, jz4780_nemc_methods, + sizeof(struct jz4780_nemc_softc), simplebus_driver); +DRIVER_MODULE(jz4780_nemc, simplebus, jz4780_nemc_driver, + jz4780_nemc_devclass, 0, 0); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_nemc.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_ohci.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_ohci.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_ohci.c (revision 308868) @@ -0,0 +1,318 @@ +/*- + * Copyright (c) 2015, Alexander Kabaev + * Copyright (c) 2009, Oleksandr Tymoshenko + * 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 unmodified, 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include +#include + +#include +#include +#include +#include + +#include +#include + +#include + +#include +#include + +static int jz4780_ohci_attach(device_t dev); +static int jz4780_ohci_detach(device_t dev); +static int jz4780_ohci_probe(device_t dev); + +struct jz4780_ohci_softc +{ + struct ohci_softc sc_ohci; + struct gpiobus_pin *gpio_vbus; + clk_t clk; +}; + +static int +jz4780_ohci_probe(device_t dev) +{ + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-ohci")) + return (ENXIO); + + device_set_desc(dev, "Ingenic JZ4780 OHCI"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jz4780_ohci_vbus_gpio_enable(device_t dev, struct jz4780_ohci_softc *sc) +{ + struct gpiobus_pin *gpio_vbus; + int error; + + error = ofw_gpiobus_parse_gpios(dev, "ingenic,vbus-gpio", &gpio_vbus); + /* + * The pin can be mapped already by other device. Assume it also has need + * activated and proceed happily. + */ + if (error <= 0) + return (0); + + sc->gpio_vbus = gpio_vbus; + if (error > 1) { + device_printf(dev, "too many vbus gpios\n"); + return (ENXIO); + } + + if (sc->gpio_vbus != NULL) { + error = GPIO_PIN_SET(sc->gpio_vbus->dev, sc->gpio_vbus->pin, 1); + if (error != 0) { + device_printf(dev, "Cannot configure GPIO pin %d on %s\n", + sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev)); + return (error); + } + + error = GPIO_PIN_SETFLAGS(sc->gpio_vbus->dev, sc->gpio_vbus->pin, + GPIO_PIN_OUTPUT); + if (error != 0) { + device_printf(dev, "Cannot configure GPIO pin %d on %s\n", + sc->gpio_vbus->pin, device_get_nameunit(sc->gpio_vbus->dev)); + return (error); + } + } + return (0); +} + +static int +jz4780_ohci_clk_enable(device_t dev) +{ + struct jz4780_ohci_softc *sc; + int err; + + sc = device_get_softc(dev); + + err = clk_get_by_ofw_index(dev, 0, 0, &sc->clk); + if (err != 0) { + device_printf(dev, "unable to lookup device clock\n"); + return (err); + } + err = clk_enable(sc->clk); + if (err != 0) { + device_printf(dev, "unable to enable device clock\n"); + return (err); + } + err = clk_set_freq(sc->clk, 48000000, 0); + if (err != 0) { + device_printf(dev, "unable to set device clock to 48 kHZ\n"); + return (err); + } + return (0); +} + +static int +jz4780_ohci_attach(device_t dev) +{ + struct jz4780_ohci_softc *sc = device_get_softc(dev); + int err; + int rid; + + /* initialize some bus fields */ + sc->sc_ohci.sc_bus.parent = dev; + sc->sc_ohci.sc_bus.devices = sc->sc_ohci.sc_devices; + sc->sc_ohci.sc_bus.devices_max = OHCI_MAX_DEVICES; + sc->sc_ohci.sc_bus.dma_bits = 32; + + /* get all DMA memory */ + if (usb_bus_mem_alloc_all(&sc->sc_ohci.sc_bus, + USB_GET_DMA_TAG(dev), &ohci_iterate_hw_softc)) { + return (ENOMEM); + } + + sc->sc_ohci.sc_dev = dev; + + /* frob vbus gpio */ + err = jz4780_ohci_vbus_gpio_enable(dev, sc); + if (err) + goto error; + + err = jz4780_ohci_clk_enable(dev); + if (err) + goto error; + + rid = 0; + sc->sc_ohci.sc_io_res = bus_alloc_resource_any(dev, SYS_RES_MEMORY, &rid, + RF_ACTIVE); + if (sc->sc_ohci.sc_io_res == NULL) { + err = ENOMEM; + goto error; + } + sc->sc_ohci.sc_io_tag = rman_get_bustag(sc->sc_ohci.sc_io_res); + sc->sc_ohci.sc_io_hdl = rman_get_bushandle(sc->sc_ohci.sc_io_res); + sc->sc_ohci.sc_io_size = rman_get_size(sc->sc_ohci.sc_io_res); + + rid = 0; + sc->sc_ohci.sc_irq_res = bus_alloc_resource_any(dev, SYS_RES_IRQ, &rid, + RF_ACTIVE); + if (sc->sc_ohci.sc_irq_res == NULL) { + err = ENOMEM; + goto error; + } + + if (jz4780_ohci_enable() != 0) { + device_printf(dev, "CGU failed to enable OHCI\n"); + err = ENXIO; + goto error; + } + + sc->sc_ohci.sc_bus.bdev = device_add_child(dev, "usbus", -1); + if (sc->sc_ohci.sc_bus.bdev == NULL) { + err = ENOMEM; + goto error; + } + device_set_ivars(sc->sc_ohci.sc_bus.bdev, &sc->sc_ohci.sc_bus); + + err = bus_setup_intr(dev, sc->sc_ohci.sc_irq_res, + INTR_TYPE_BIO | INTR_MPSAFE, NULL, + (driver_intr_t *)ohci_interrupt, sc, &sc->sc_ohci.sc_intr_hdl); + if (err) { + err = ENXIO; + goto error; + } + + strlcpy(sc->sc_ohci.sc_vendor, "Ingenic", sizeof(sc->sc_ohci.sc_vendor)); + bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, OHCI_CONTROL, 0); + + err = ohci_init(&sc->sc_ohci); + if (!err) + err = device_probe_and_attach(sc->sc_ohci.sc_bus.bdev); + + if (err) + goto error; + return (0); + +error: + if (err) + jz4780_ohci_detach(dev); + return (err); +} + +static int +jz4780_ohci_detach(device_t dev) +{ + struct jz4780_ohci_softc *sc = device_get_softc(dev); + device_t bdev; + + if (sc->sc_ohci.sc_bus.bdev) { + bdev = sc->sc_ohci.sc_bus.bdev; + device_detach(bdev); + device_delete_child(dev, bdev); + } + /* during module unload there are lots of children leftover */ + device_delete_children(dev); + + /* + * Put the controller into reset, then disable clocks and do + * the MI tear down. We have to disable the clocks/hardware + * after we do the rest of the teardown. We also disable the + * clocks in the opposite order we acquire them, but that + * doesn't seem to be absolutely necessary. We free up the + * clocks after we disable them, so the system could, in + * theory, reuse them. + */ + if (sc->sc_ohci.sc_io_res != NULL) { + bus_space_write_4(sc->sc_ohci.sc_io_tag, sc->sc_ohci.sc_io_hdl, + OHCI_CONTROL, 0); + } + + if (sc->sc_ohci.sc_intr_hdl) { + bus_teardown_intr(dev, sc->sc_ohci.sc_irq_res, sc->sc_ohci.sc_intr_hdl); + sc->sc_ohci.sc_intr_hdl = NULL; + } + + if (sc->sc_ohci.sc_irq_res && sc->sc_ohci.sc_intr_hdl) { + /* + * only call ohci_detach() after ohci_init() + */ + ohci_detach(&sc->sc_ohci); + + bus_release_resource(dev, SYS_RES_IRQ, 0, sc->sc_ohci.sc_irq_res); + sc->sc_ohci.sc_irq_res = NULL; + } + if (sc->sc_ohci.sc_io_res) { + bus_release_resource(dev, SYS_RES_MEMORY, 0, sc->sc_ohci.sc_io_res); + sc->sc_ohci.sc_io_res = NULL; + sc->sc_ohci.sc_io_tag = 0; + sc->sc_ohci.sc_io_hdl = 0; + } + + if (sc->clk != NULL) + clk_release(sc->clk); + + usb_bus_mem_free_all(&sc->sc_ohci.sc_bus, &ohci_iterate_hw_softc); + free(sc->gpio_vbus, M_DEVBUF); + return (0); +} + +static device_method_t ohci_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_ohci_probe), + DEVMETHOD(device_attach, jz4780_ohci_attach), + DEVMETHOD(device_detach, jz4780_ohci_detach), + DEVMETHOD(device_suspend, bus_generic_suspend), + DEVMETHOD(device_resume, bus_generic_resume), + DEVMETHOD(device_shutdown, bus_generic_shutdown), + + DEVMETHOD_END +}; + +static driver_t ohci_driver = { + .name = "ohci", + .methods = ohci_methods, + .size = sizeof(struct jz4780_ohci_softc), +}; + +static devclass_t ohci_devclass; + +DRIVER_MODULE(ohci, simplebus, ohci_driver, ohci_devclass, 0, 0); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_ohci.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_pinctrl.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_pinctrl.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_pinctrl.c (revision 308868) @@ -0,0 +1,260 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + */ + +/* + * Ingenic JZ4780 pinctrl driver. + */ + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +#include +#include +#include + +#include + +#include "jz4780_gpio_if.h" + +struct jz4780_pinctrl_softc { + struct simplebus_softc ssc; + device_t dev; +}; + +#define CHIP_REG_STRIDE 256 +#define CHIP_REG_OFFSET(base, chip) ((base) + (chip) * CHIP_REG_STRIDE) + +static int +jz4780_pinctrl_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-pinctrl")) + return (ENXIO); + + device_set_desc(dev, "Ingenic JZ4780 GPIO"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jz4780_pinctrl_attach(device_t dev) +{ + struct jz4780_pinctrl_softc *sc; + struct resource_list *rs; + struct resource_list_entry *re; + phandle_t dt_parent, dt_child; + int i, ret; + + sc = device_get_softc(dev); + sc->dev = dev; + + /* + * Fetch our own resource list to dole memory between children + */ + rs = BUS_GET_RESOURCE_LIST(device_get_parent(dev), dev); + if (rs == NULL) + return (ENXIO); + re = resource_list_find(rs, SYS_RES_MEMORY, 0); + if (re == NULL) + return (ENXIO); + + simplebus_init(dev, 0); + + /* Iterate over this node children, looking for pin controllers */ + dt_parent = ofw_bus_get_node(dev); + i = 0; + for (dt_child = OF_child(dt_parent); dt_child != 0; + dt_child = OF_peer(dt_child)) { + struct simplebus_devinfo *ndi; + device_t child; + bus_addr_t phys; + bus_size_t size; + + /* Add gpio controller child */ + if (!OF_hasprop(dt_child, "gpio-controller")) + continue; + child = simplebus_add_device(dev, dt_child, 0, NULL, -1, NULL); + if (child == NULL) + break; + /* Setup child resources */ + phys = CHIP_REG_OFFSET(re->start, i); + size = CHIP_REG_STRIDE; + if (phys + size - 1 <= re->end) { + ndi = device_get_ivars(child); + resource_list_add(&ndi->rl, SYS_RES_MEMORY, 0, + phys, phys + size - 1, size); + } + i++; + } + + ret = bus_generic_attach(dev); + if (ret == 0) { + fdt_pinctrl_register(dev, "ingenic,pins"); + fdt_pinctrl_configure_tree(dev); + } + return (ret); +} + +static int +jz4780_pinctrl_detach(device_t dev) +{ + + bus_generic_detach(dev); + return (0); +} + +struct jx4780_bias_prop { + const char *name; + uint32_t bias; +}; + +static struct jx4780_bias_prop jx4780_bias_table[] = { + { "bias-disable", 0 }, + { "bias-pull-up", GPIO_PIN_PULLUP }, + { "bias-pull-down", GPIO_PIN_PULLDOWN }, +}; + +static int +jz4780_pinctrl_parse_pincfg(phandle_t pincfgxref, uint32_t *bias_value) +{ + phandle_t pincfg_node; + int i; + + pincfg_node = OF_node_from_xref(pincfgxref); + for (i = 0; i < nitems(jx4780_bias_table); i++) { + if (OF_hasprop(pincfg_node, jx4780_bias_table[i].name)) { + *bias_value = jx4780_bias_table[i].bias; + return 0; + } + } + + return -1; +} + +static device_t +jz4780_pinctrl_chip_lookup(struct jz4780_pinctrl_softc *sc, phandle_t chipxref) +{ + device_t chipdev; + + chipdev = OF_device_from_xref(chipxref); + return chipdev; +} + +static int +jz4780_pinctrl_configure_pins(device_t dev, phandle_t cfgxref) +{ + struct jz4780_pinctrl_softc *sc = device_get_softc(dev); + device_t chip; + phandle_t node; + ssize_t i, len; + uint32_t *value, *pconf; + int result; + + node = OF_node_from_xref(cfgxref); + + len = OF_getencprop_alloc(node, "ingenic,pins", sizeof(uint32_t) * 4, + (void **)&value); + if (len < 0) { + device_printf(dev, + "missing ingenic,pins attribute in FDT\n"); + return (ENXIO); + } + + pconf = value; + result = EINVAL; + for (i = 0; i < len; i++, pconf += 4) { + uint32_t bias; + + /* Lookup the chip that handles this configuration */ + chip = jz4780_pinctrl_chip_lookup(sc, pconf[0]); + if (chip == NULL) { + device_printf(dev, + "invalid gpio controller reference in FDT\n"); + goto done; + } + + if (jz4780_pinctrl_parse_pincfg(pconf[3], &bias) != 0) { + device_printf(dev, + "invalid pin bias for pin %u on %s in FDT\n", + pconf[1], ofw_bus_get_name(chip)); + goto done; + } + + result = JZ4780_GPIO_CONFIGURE_PIN(chip, pconf[1], pconf[2], + bias); + if (result != 0) { + device_printf(dev, + "failed to configure pin %u on %s\n", pconf[1], + ofw_bus_get_name(chip)); + goto done; + } + } + + result = 0; +done: + free(value, M_OFWPROP); + return (result); +} + + +static device_method_t jz4780_pinctrl_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_pinctrl_probe), + DEVMETHOD(device_attach, jz4780_pinctrl_attach), + DEVMETHOD(device_detach, jz4780_pinctrl_detach), + + /* fdt_pinctrl interface */ + DEVMETHOD(fdt_pinctrl_configure, jz4780_pinctrl_configure_pins), + + DEVMETHOD_END +}; + +static devclass_t jz4780_pinctrl_devclass; +DEFINE_CLASS_1(pinctrl, jz4780_pinctrl_driver, jz4780_pinctrl_methods, + sizeof(struct jz4780_pinctrl_softc), simplebus_driver); +EARLY_DRIVER_MODULE(pinctrl, simplebus, jz4780_pinctrl_driver, + jz4780_pinctrl_devclass, 0, 0, BUS_PASS_INTERRUPT + BUS_PASS_ORDER_LATE); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_pinctrl.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_pinctrl.h =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_pinctrl.h (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_pinctrl.h (revision 308868) @@ -0,0 +1,33 @@ +/*- + * Copyright 2015 Alexander Kabaev + * 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. + * + * $FreeBSD$ + */ + +#ifndef _MIPS_INGENIC_JZ4780_PINCTRL_H +#define _MIPS_INGENIC_JZ4780_PINCTRL_H + + +#endif /* _MIPS_INGENIC_JZ4780_PINCTRL_H */ Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_pinctrl.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_regs.h =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_regs.h (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_regs.h (revision 308868) @@ -0,0 +1,787 @@ +/* $NetBSD: ingenic_regs.h,v 1.22 2015/10/08 17:54:30 macallan Exp $ */ + +/*- + * Copyright (c) 2014 Michael Lorenz + * 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 NETBSD FOUNDATION, INC. 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 FOUNDATION 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. + * + * $FreeBSD$ + */ + +#ifndef JZ4780_REGS_H +#define JZ4780_REGS_H + +/* for mips_wbflush() */ +#include + +/* UARTs, mostly 16550 compatible with 32bit spaced registers */ +#define JZ_UART0 0x10030000 +#define JZ_UART1 0x10031000 +#define JZ_UART2 0x10032000 +#define JZ_UART3 0x10033000 +#define JZ_UART4 0x10034000 + +/* LCD controller base addresses, registers are in jzfb_regs.h */ +#define JZ_LCDC0_BASE 0x13050000 +#define JZ_LCDC1_BASE 0x130a0000 + +/* TCU unit base address */ +#define JZ_TCU_BASE 0x10002000 + +/* Watchdog */ +#define JZ_WDOG_TDR 0x00000000 /* compare */ +#define JZ_WDOG_TCER 0x00000004 + #define TCER_ENABLE 0x01 /* enable counter */ +#define JZ_WDOG_TCNT 0x00000008 /* 16bit up count */ +#define JZ_WDOG_TCSR 0x0000000c + #define TCSR_PCK_EN 0x01 /* PCLK */ + #define TCSR_RTC_EN 0x02 /* RTCCLK - 32.768kHz */ + #define TCSR_EXT_EN 0x04 /* EXTCLK - 48MHz */ + #define TCSR_PRESCALE_M 0x38 + #define TCSR_DIV_1 0x00 + #define TCSR_DIV_4 0x08 + #define TCSR_DIV_16 0x10 + #define TCSR_DIV_64 0x18 + #define TCSR_DIV_256 0x20 + #define TCSR_DIV_1024 0x28 + +/* timers and PWMs */ +#define JZ_TC_TER 0x00000010 /* TC enable reg, ro */ +#define JZ_TC_TESR 0x00000014 /* TC enable set reg. */ + #define TESR_TCST0 0x0001 /* enable counter 0 */ + #define TESR_TCST1 0x0002 /* enable counter 1 */ + #define TESR_TCST2 0x0004 /* enable counter 2 */ + #define TESR_TCST3 0x0008 /* enable counter 3 */ + #define TESR_TCST4 0x0010 /* enable counter 4 */ + #define TESR_TCST5 0x0020 /* enable counter 5 */ + #define TESR_TCST6 0x0040 /* enable counter 6 */ + #define TESR_TCST7 0x0080 /* enable counter 7 */ + #define TESR_OST 0x8000 /* enable OST */ +#define JZ_TC_TECR 0x00000018 /* TC enable clear reg. */ +#define JZ_TC_TFR 0x00000020 + #define TFR_FFLAG0 0x00000001 /* channel 0 */ + #define TFR_FFLAG1 0x00000002 /* channel 1 */ + #define TFR_FFLAG2 0x00000004 /* channel 2 */ + #define TFR_FFLAG3 0x00000008 /* channel 3 */ + #define TFR_FFLAG4 0x00000010 /* channel 4 */ + #define TFR_FFLAG5 0x00000020 /* channel 5 */ + #define TFR_FFLAG6 0x00000040 /* channel 6 */ + #define TFR_FFLAG7 0x00000080 /* channel 7 */ + #define TFR_OSTFLAG 0x00008000 /* OS timer */ +#define JZ_TC_TFSR 0x00000024 /* timer flag set */ +#define JZ_TC_TFCR 0x00000028 /* timer flag clear */ +#define JZ_TC_TMR 0x00000030 /* timer flag mask */ + #define TMR_FMASK(n) (1 << (n)) + #define TMR_HMASK(n) (1 << ((n) + 16)) +#define JZ_TC_TMSR 0x00000034 /* timer flag mask set */ +#define JZ_TC_TMCR 0x00000038 /* timer flag mask clear*/ + +#define JZ_TC_TDFR(n) (0x00000040 + (n * 0x10)) /* FULL compare */ +#define JZ_TC_TDHR(n) (0x00000044 + (n * 0x10)) /* HALF compare */ +#define JZ_TC_TCNT(n) (0x00000048 + (n * 0x10)) /* count */ + +#define JZ_TC_TCSR(n) (0x0000004c + (n * 0x10)) +/* same bits as in JZ_WDOG_TCSR */ + +/* operating system timer */ +#define JZ_OST_DATA 0x000000e0 /* compare */ +#define JZ_OST_CNT_LO 0x000000e4 +#define JZ_OST_CNT_HI 0x000000e8 +#define JZ_OST_CTRL 0x000000ec + #define OSTC_PCK_EN 0x0001 /* use PCLK */ + #define OSTC_RTC_EN 0x0002 /* use RTCCLK */ + #define OSTC_EXT_EN 0x0004 /* use EXTCLK */ + #define OSTC_PRESCALE_M 0x0038 + #define OSTC_DIV_1 0x0000 + #define OSTC_DIV_4 0x0008 + #define OSTC_DIV_16 0x0010 + #define OSTC_DIV_64 0x0018 + #define OSTC_DIV_256 0x0020 + #define OSTC_DIV_1024 0x0028 + #define OSTC_SHUTDOWN 0x0200 + #define OSTC_MODE 0x8000 /* 0 - reset to 0 when = OST_DATA */ +#define JZ_OST_CNT_U32 0x000000fc /* copy of CNT_HI when reading CNT_LO */ + +static inline void +writereg(uint32_t reg, uint32_t val) +{ + *(volatile int32_t *)MIPS_PHYS_TO_KSEG1(reg) = val; + mips_wbflush(); +} + +static inline uint32_t +readreg(uint32_t reg) +{ + mips_wbflush(); + return *(volatile int32_t *)MIPS_PHYS_TO_KSEG1(reg); +} + +/* Clock management */ +#define JZ_CGU_BASE 0x10000000 + +#define JZ_CPCCR 0x00000000 /* Clock Control Register */ + #define JZ_PDIV_M 0x000f0000 /* PCLK divider mask */ + #define JZ_PDIV_S 16 /* PCLK divider shift */ + #define JZ_CDIV_M 0x0000000f /* CPU clock divider mask */ + #define JZ_CDIV_S 0 /* CPU clock divider shift */ +#define JZ_CPAPCR 0x00000010 /* APLL */ +#define JZ_CPMPCR 0x00000014 /* MPLL */ +#define JZ_CPEPCR 0x00000018 /* EPLL */ +#define JZ_CPVPCR 0x0000001C /* VPLL */ + #define JZ_PLLM_S 19 /* PLL multiplier shift */ + #define JZ_PLLM_M 0xfff80000 /* PLL multiplier mask */ + #define JZ_PLLN_S 13 /* PLL divider shift */ + #define JZ_PLLN_M 0x0007e000 /* PLL divider mask */ + #define JZ_PLLP_S 9 /* PLL postdivider shift */ + #define JZ_PLLP_M 0x00001700 /* PLL postdivider mask */ + #define JZ_PLLON 0x00000010 /* PLL is on and stable */ + #define JZ_PLLBP 0x00000002 /* PLL bypass */ + #define JZ_PLLEN 0x00000001 /* PLL enable */ +#define JZ_CLKGR0 0x00000020 /* Clock Gating Registers */ + #define CLK_NEMC (1 << 0) + #define CLK_BCH (1 << 1) + #define CLK_OTG0 (1 << 2) + #define CLK_MSC0 (1 << 3) + #define CLK_SSI0 (1 << 4) + #define CLK_SMB0 (1 << 5) + #define CLK_SMB1 (1 << 6) + #define CLK_SCC (1 << 7) + #define CLK_AIC (1 << 8) + #define CLK_TSSI0 (1 << 9) + #define CLK_OWI (1 << 10) + #define CLK_MSC1 (1 << 11) + #define CLK_MSC2 (1 << 12) + #define CLK_KBC (1 << 13) + #define CLK_SADC (1 << 14) + #define CLK_UART0 (1 << 15) + #define CLK_UART1 (1 << 16) + #define CLK_UART2 (1 << 17) + #define CLK_UART3 (1 << 18) + #define CLK_SSI1 (1 << 19) + #define CLK_SSI2 (1 << 20) + #define CLK_PDMA (1 << 21) + #define CLK_GPS (1 << 22) + #define CLK_MAC (1 << 23) + #define CLK_UHC (1 << 24) + #define CLK_SMB2 (1 << 25) + #define CLK_CIM (1 << 26) + #define CLK_TVE (1 << 27) + #define CLK_LCD (1 << 28) + #define CLK_IPU (1 << 29) + #define CLK_DDR0 (1 << 30) + #define CLK_DDR1 (1 << 31) +#define JZ_CLKGR1 0x00000028 /* Clock Gating Registers */ + #define CLK_SMB3 (1 << 0) + #define CLK_TSSI1 (1 << 1) + #define CLK_VPU (1 << 2) + #define CLK_PCM (1 << 3) + #define CLK_GPU (1 << 4) + #define CLK_COMPRESS (1 << 5) + #define CLK_AIC1 (1 << 6) + #define CLK_GPVLC (1 << 7) + #define CLK_OTG1 (1 << 8) + #define CLK_HDMI (1 << 9) + #define CLK_UART4 (1 << 10) + #define CLK_AHB_MON (1 << 11) + #define CLK_SMB4 (1 << 12) + #define CLK_DES (1 << 13) + #define CLK_X2D (1 << 14) + #define CLK_P1 (1 << 15) +#define JZ_DDCDR 0x0000002c /* DDR clock divider register */ +#define JZ_VPUCDR 0x00000030 /* VPU clock divider register */ +#define JZ_I2SCDR 0x00000060 /* I2S device clock divider register */ +#define JZ_I2S1CDR 0x000000a0 /* I2S device clock divider register */ +#define JZ_USBCDR 0x00000050 /* OTG PHY clock divider register */ +#define JZ_LP0CDR 0x00000054 /* LCD0 pix clock divider register */ +#define JZ_LP1CDR 0x00000064 /* LCD1 pix clock divider register */ +#define JZ_MSC0CDR 0x00000068 /* MSC0 clock divider register */ +#define JZ_MSC1CDR 0x000000a4 /* MSC1 clock divider register */ +#define JZ_MSC2CDR 0x000000a8 /* MSC2 clock divider register */ + #define MSCCDR_SCLK_A 0x40000000 + #define MSCCDR_MPLL 0x80000000 + #define MSCCDR_CE 0x20000000 + #define MSCCDR_BUSY 0x10000000 + #define MSCCDR_STOP 0x08000000 + #define MSCCDR_PHASE 0x00008000 /* 0 - 90deg phase, 1 - 180 */ + #define MSCCDR_DIV_M 0x000000ff /* src / ((div + 1) * 2) */ + #define UHCCDR_DIV_M 0x000000ff +#define JZ_UHCCDR 0x0000006c /* UHC 48M clock divider register */ + #define UHCCDR_SCLK_A 0x00000000 + #define UHCCDR_MPLL 0x40000000 + #define UHCCDR_EPLL 0x80000000 + #define UHCCDR_OTG_PHY 0xc0000000 + #define UHCCDR_CLK_MASK 0xc0000000 + #define UHCCDR_CE 0x20000000 + #define UHCCDR_BUSY 0x10000000 + #define UHCCDR_STOP 0x08000000 + #define UHCCDR_DIV_M 0x000000ff + #define UHCCDR_DIV(d) (d) +#define JZ_SSICDR 0x00000074 /* SSI clock divider register */ +#define JZ_CIMCDR 0x0000007c /* CIM MCLK clock divider register */ +#define JZ_PCMCDR 0x00000084 /* PCM device clock divider register */ +#define JZ_GPUCDR 0x00000088 /* GPU clock divider register */ +#define JZ_HDMICDR 0x0000008c /* HDMI clock divider register */ +#define JZ_BCHCDR 0x000000ac /* BCH clock divider register */ +#define JZ_CPM_INTR 0x000000b0 /* CPM interrupt register */ +#define JZ_CPM_INTRE 0x000000b4 /* CPM interrupt enable register */ +#define JZ_CPSPR 0x00000034 /* CPM scratch register */ +#define JZ_CPSRPR 0x00000038 /* CPM scratch protected register */ +#define JZ_USBPCR 0x0000003c /* USB parameter control register */ + #define PCR_USB_MODE 0x80000000 /* 1 - otg */ + #define PCR_AVLD_REG 0x40000000 + #define PCR_IDPULLUP_MASK 0x30000000 + #define PCR_INCR_MASK 0x08000000 + #define PCR_TCRISETUNE 0x04000000 + #define PCR_COMMONONN 0x02000000 + #define PCR_VBUSVLDEXT 0x01000000 + #define PCR_VBUSVLDEXTSEL 0x00800000 + #define PCR_POR 0x00400000 + #define PCR_SIDDQ 0x00200000 + #define PCR_OTG_DISABLE 0x00100000 + #define PCR_COMPDISTN_M 0x000e0000 + #define PCR_OTGTUNE 0x0001c000 + #define PCR_SQRXTUNE 0x00003800 + #define PCR_TXFSLSTUNE 0x00000780 + #define PCR_TXPREEMPHTUNE 0x00000040 + #define PCR_TXHSXVTUNE 0x00000030 + #define PCR_TXVREFTUNE 0x0000000f +#define JZ_USBRDT 0x00000040 /* Reset detect timer register */ + #define USBRDT_USBRDT_SHIFT 0 + #define USBRDT_USBRDT_WIDTH 23 + #define USBRDT_VBFIL_LD_EN 0x01000000 +#define JZ_USBVBFIL 0x00000044 /* USB jitter filter register */ + #define USBVBFIL_IDDIGFIL_SHIFT 16 + #define USBVBFIL_IDDIGFIL_WIDTH 16 + #define USBVBFIL_USBVBFIL_SHIFT 0 + #define USBVBFIL_USBVBFIL_WIDTH 16 +#define JZ_USBPCR1 0x00000048 /* USB parameter control register 1 */ + #define PCR_SYNOPSYS 0x10000000 /* Mentor mode otherwise */ + #define PCR_REFCLK_CORE 0x08000000 + #define PCR_REFCLK_XO25 0x04000000 + #define PCR_REFCLK_CO 0x00000000 + #define PCR_REFCLK_M 0x0c000000 + #define PCR_CLK_M 0x03000000 /* clock */ + #define PCR_CLK_192 0x03000000 /* 19.2MHz */ + #define PCR_CLK_48 0x02000000 /* 48MHz */ + #define PCR_CLK_24 0x01000000 /* 24MHz */ + #define PCR_CLK_12 0x00000000 /* 12MHz */ + #define PCR_DMPD1 0x00800000 /* pull down D- on port 1 */ + #define PCR_DPPD1 0x00400000 /* pull down D+ on port 1 */ + #define PCR_PORT0_RST 0x00200000 /* port 0 reset */ + #define PCR_PORT1_RST 0x00100000 /* port 1 reset */ + #define PCR_WORD_I_F0 0x00080000 /* 1: 16bit/30M, 8/60 otherw. */ + #define PCR_WORD_I_F1 0x00040000 /* same for port 1 */ + #define PCR_COMPDISTUNE 0x00038000 /* disconnect threshold */ + #define PCR_SQRXTUNE1 0x00007000 /* squelch threshold */ + #define PCR_TXFSLSTUNE1 0x00000f00 /* FS/LS impedance adj. */ + #define PCR_TXPREEMPH 0x00000080 /* HS transm. pre-emphasis */ + #define PCR_TXHSXVTUNE1 0x00000060 /* dp/dm voltage adj. */ + #define PCR_TXVREFTUNE1 0x00000017 /* HS DC voltage adj. */ + #define PCR_TXRISETUNE1 0x00000001 /* rise/fall wave adj. */ + +/* power manager */ +#define JZ_LPCR 0x00000004 + #define LPCR_PD_SCPU (1u << 31) /* CPU1 power down */ + #define LPCR_PD_VPU (1u << 30) /* VPU power down */ + #define LPCR_PD_GPU (1u << 29) /* GPU power down */ + #define LPCR_PD_GPS (1u << 28) /* GPS power down */ + #define LPCR_SCPUS (1u << 27) /* CPU1 power down status */ + #define LPCR_VPUS (1u << 26) /* VPU power down status */ + #define LPCR_GPUS (1u << 25) /* GPU power down status */ + #define LPCR_GPSS (1u << 24) /* GPS power down status */ + #define LPCR_GPU_IDLE (1u << 20) /* GPU idle status */ + #define LPCR_PST_SHIFT 8 /* Power stability time */ + #define LPCR_PST_MASK (0xFFFu << 8) + #define LPCR_DUTY_SHIFT 3 /* CPU clock duty */ + #define LPCR_DUTY_MASK (0x1Fu << 3) + #define LPCR_DOZE (1u << 2) /* Doze mode */ + #define LPCR_LPM_SHIFT 0 /* Low power mode */ + #define LPCR_LPM_MASK (0x03u << 0) + +#define JZ_OPCR 0x00000024 /* Oscillator Power Control Reg. */ + #define OPCR_IDLE_DIS 0x80000000 /* don't stop CPU clk on idle */ + #define OPCR_GPU_CLK_ST 0x40000000 /* stop GPU clock */ + #define OPCR_L2CM_M 0x0c000000 + #define OPCR_L2CM_ON 0x00000000 /* L2 stays on in sleep */ + #define OPCR_L2CM_RET 0x04000000 /* L2 retention mode in sleep */ + #define OPCR_L2CM_OFF 0x08000000 /* L2 powers down in sleep */ + #define OPCR_SPENDN0 0x00000080 /* 0 - OTG port forced down */ + #define OPCR_SPENDN1 0x00000040 /* 0 - UHC port forced down */ + #define OPCR_BUS_MODE 0x00000020 /* 1 - bursts */ + #define OPCR_O1SE 0x00000010 /* EXTCLK on in sleep */ + #define OPCR_PD 0x00000008 /* P0 down in sleep */ + #define OPCR_ERCS 0x00000004 /* 1 RTCCLK, 0 EXTCLK/512 */ + #define OPCR_CPU_MODE 0x00000002 /* 1 access 'accelerated' */ + #define OPCR_OSE 0x00000001 /* disable EXTCLK */ + +#define JZ_SPCR0 0x000000b8 /* SRAM Power Control Registers */ +#define JZ_SPCR1 0x000000bc +#define JZ_SRBC 0x000000c4 /* Soft Reset & Bus Control */ + #define SRBC_UHC_SR 0x00004000 /* UHC soft reset*/ + +/* + * random number generator + * + * Its function currently isn't documented by Ingenic. + * However, testing suggests that it works as expected. + */ +#define JZ_ERNG 0x000000d8 +#define JZ_RNG 0x000000dc + +/* Interrupt controller */ +#define JZ_ICBASE 0x10001000 /* IC base address */ +#define JZ_ICSR0 0x00000000 /* raw IRQ line status */ +#define JZ_ICMR0 0x00000004 /* IRQ mask, 1 masks IRQ */ +#define JZ_ICMSR0 0x00000008 /* sets bits in mask register */ +#define JZ_ICMCR0 0x0000000c /* clears bits in mask register */ +#define JZ_ICPR0 0x00000010 /* line status after masking */ + +#define JZ_ICSR1 0x00000020 /* raw IRQ line status */ +#define JZ_ICMR1 0x00000024 /* IRQ mask, 1 masks IRQ */ +#define JZ_ICMSR1 0x00000028 /* sets bits in mask register */ +#define JZ_ICMCR1 0x0000002c /* clears bits in maks register */ +#define JZ_ICPR1 0x00000030 /* line status after masking */ + +#define JZ_DSR0 0x00000034 /* source for PDMA */ +#define JZ_DMR0 0x00000038 /* mask for PDMA */ +#define JZ_DPR0 0x0000003c /* pending for PDMA */ + +#define JZ_DSR1 0x00000040 /* source for PDMA */ +#define JZ_DMR1 0x00000044 /* mask for PDMA */ +#define JZ_DPR1 0x00000048 /* pending for PDMA */ + +/* memory controller */ +#define JZ_DMMAP0 0x13010024 +#define JZ_DMMAP1 0x13010028 + #define DMMAP_BASE 0x0000ff00 /* base PADDR of memory chunk */ + #define DMMAP_MASK 0x000000ff /* mask which bits of PADDR are + * constant */ +/* USB controllers */ +#define JZ_EHCI_BASE 0x13490000 +#define JZ_EHCI_REG_UTMI_BUS 0x000000b0 + #define UTMI_BUS_WIDTH 0x00000040 +#define JZ_OHCI_BASE 0x134a0000 + +#define JZ_DWC2_BASE 0x13500000 +#define JZ_DWC2_GUSBCFG 0 + +/* Ethernet */ +#define JZ_DME_BASE 0x16000000 +#define JZ_DME_IO 0 +#define JZ_DME_DATA 2 + +/* GPIO */ +#define JZ_GPIO_A_BASE 0x10010000 +#define JZ_GPIO_B_BASE 0x10010100 +#define JZ_GPIO_C_BASE 0x10010200 +#define JZ_GPIO_D_BASE 0x10010300 +#define JZ_GPIO_E_BASE 0x10010400 +#define JZ_GPIO_F_BASE 0x10010500 + +/* GPIO registers per port */ +#define JZ_GPIO_PIN 0x00000000 /* pin level register */ +/* 0 - normal gpio, 1 - interrupt */ +#define JZ_GPIO_INT 0x00000010 /* interrupt register */ +#define JZ_GPIO_INTS 0x00000014 /* interrupt set register */ +#define JZ_GPIO_INTC 0x00000018 /* interrupt clear register */ +/* + * INT == 1: 1 disables interrupt + * INT == 0: device select, see below + */ +#define JZ_GPIO_MASK 0x00000020 /* port mask register */ +#define JZ_GPIO_MASKS 0x00000024 /* port mask set register */ +#define JZ_GPIO_MASKC 0x00000028 /* port mask clear register */ +/* + * INT == 1: 0 - level triggered, 1 - edge triggered + * INT == 0: 0 - device select, see below + */ +#define JZ_GPIO_PAT1 0x00000030 /* pattern 1 register */ +#define JZ_GPIO_PAT1S 0x00000034 /* pattern 1 set register */ +#define JZ_GPIO_PAT1C 0x00000038 /* pattern 1 clear register */ +/* + * INT == 1: + * PAT1 == 0: 0 - trigger on low, 1 - trigger on high + * PAT0 == 1: 0 - trigger on falling edge, 1 - trigger on rising edge + * INT == 0: + * MASK == 0: + * PAT1 == 0: 0 - device 0, 1 - device 1 + * PAT0 == 1: 0 - device 2, 1 - device 3 + * MASK == 1: + * PAT1 == 0: set gpio output + * PAT1 == 1: pin is input + */ +#define JZ_GPIO_PAT0 0x00000040 /* pattern 0 register */ +#define JZ_GPIO_PAT0S 0x00000044 /* pattern 0 set register */ +#define JZ_GPIO_PAT0C 0x00000048 /* pattern 0 clear register */ +/* 1 - interrupt happened */ +#define JZ_GPIO_FLAG 0x00000050 /* flag register */ +#define JZ_GPIO_FLAGC 0x00000058 /* flag clear register */ +/* 1 - disable pull up/down resistors */ +#define JZ_GPIO_DPULL 0x00000070 /* pull disable register */ +#define JZ_GPIO_DPULLS 0x00000074 /* pull disable set register */ +#define JZ_GPIO_DPULLC 0x00000078 /* pull disable clear register */ +/* the following are uncommented in the manual */ +#define JZ_GPIO_DRVL 0x00000080 /* drive low register */ +#define JZ_GPIO_DRVLS 0x00000084 /* drive low set register */ +#define JZ_GPIO_DRVLC 0x00000088 /* drive low clear register */ +#define JZ_GPIO_DIR 0x00000090 /* direction register */ +#define JZ_GPIO_DIRS 0x00000094 /* direction register */ +#define JZ_GPIO_DIRC 0x00000098 /* direction register */ +#define JZ_GPIO_DRVH 0x000000a0 /* drive high register */ +#define JZ_GPIO_DRVHS 0x000000a4 /* drive high set register */ +#define JZ_GPIO_DRVHC 0x000000a8 /* drive high clear register */ + +/* I2C / SMBus */ +#define JZ_SMB0_BASE 0x10050000 +#define JZ_SMB1_BASE 0x10051000 +#define JZ_SMB2_BASE 0x10052000 +#define JZ_SMB3_BASE 0x10053000 +#define JZ_SMB4_BASE 0x10054000 + +/* SMBus register offsets, per port */ +#define JZ_SMBCON 0x00 /* SMB control */ + #define JZ_STPHLD 0x80 /* Stop Hold Enable bit */ + #define JZ_SLVDIS 0x40 /* 1 - slave disabled */ + #define JZ_REST 0x20 /* 1 - allow RESTART */ + #define JZ_MATP 0x10 /* 1 - enable 10bit addr. for master */ + #define JZ_SATP 0x08 /* 1 - enable 10bit addr. for slave */ + #define JZ_SPD_M 0x06 /* bus speed control */ + #define JZ_SPD_100KB 0x02 /* 100kBit/s mode */ + #define JZ_SPD_400KB 0x04 /* 400kBit/s mode */ + #define JZ_MD 0x01 /* enable master */ +#define JZ_SMBTAR 0x04 /* SMB target address */ + #define JZ_SMATP 0x1000 /* enable 10bit master addr */ + #define JZ_SPECIAL 0x0800 /* 1 - special command */ + #define JZ_START 0x0400 /* 1 - send START */ + #define JZ_SMBTAR_M 0x03ff /* target address */ +#define JZ_SMBSAR 0x08 /* SMB slave address */ +#define JZ_SMBDC 0x10 /* SMB data buffer and command */ + #define JZ_CMD 0x100 /* 1 - read, 0 - write */ + #define JZ_DATA 0x0ff +#define JZ_SMBSHCNT 0x14 /* Standard speed SMB SCL high count */ +#define JZ_SMBSLCNT 0x18 /* Standard speed SMB SCL low count */ +#define JZ_SMBFHCNT 0x1C /* Fast speed SMB SCL high count */ +#define JZ_SMBFLCNT 0x20 /* Fast speed SMB SCL low count */ +#define JZ_SMBINTST 0x2C /* SMB Interrupt Status */ + #define JZ_ISTT 0x400 /* START or RESTART occured */ + #define JZ_ISTP 0x200 /* STOP occured */ + #define JZ_TXABT 0x40 /* ABORT occured */ + #define JZ_TXEMP 0x10 /* TX FIFO is low */ + #define JZ_TXOF 0x08 /* TX FIFO is high */ + #define JZ_RXFL 0x04 /* RX FIFO is at JZ_SMBRXTL*/ + #define JZ_RXOF 0x02 /* RX FIFO is high */ + #define JZ_RXUF 0x01 /* RX FIFO underflow */ +#define JZ_SMBINTM 0x30 /* SMB Interrupt Mask */ +#define JZ_SMBRXTL 0x38 /* SMB RxFIFO Threshold */ +#define JZ_SMBTXTL 0x3C /* SMB TxFIFO Threshold */ +#define JZ_SMBCINT 0x40 /* Clear Interrupts */ + #define JZ_CLEARALL 0x01 +#define JZ_SMBCRXUF 0x44 /* Clear RXUF Interrupt */ +#define JZ_SMBCRXOF 0x48 /* Clear RX_OVER Interrupt */ +#define JZ_SMBCTXOF 0x4C /* Clear TX_OVER Interrupt */ +#define JZ_SMBCRXREQ 0x50 /* Clear RDREQ Interrupt */ +#define JZ_SMBCTXABT 0x54 /* Clear TX_ABRT Interrupt */ +#define JZ_SMBCRXDN 0x58 /* Clear RX_DONE Interrupt */ +#define JZ_SMBCACT 0x5c /* Clear ACTIVITY Interrupt */ +#define JZ_SMBCSTP 0x60 /* Clear STOP Interrupt */ +#define JZ_SMBCSTT 0x64 /* Clear START Interrupt */ +#define JZ_SMBCGC 0x68 /* Clear GEN_CALL Interrupt */ +#define JZ_SMBENB 0x6C /* SMB Enable */ + #define JZ_ENABLE 0x01 +#define JZ_SMBST 0x70 /* SMB Status register */ + #define JZ_SLVACT 0x40 /* slave is active */ + #define JZ_MSTACT 0x20 /* master is active */ + #define JZ_RFF 0x10 /* RX FIFO is full */ + #define JZ_RFNE 0x08 /* RX FIFO not empty */ + #define JZ_TFE 0x04 /* TX FIFO is empty */ + #define JZ_TFNF 0x02 /* TX FIFO is not full */ + #define JZ_ACT 0x01 /* JZ_SLVACT | JZ_MSTACT */ +#define JZ_SMBABTSRC 0x80 /* SMB Transmit Abort Status Register */ +#define JZ_SMBDMACR 0x88 /* DMA Control Register */ +#define JZ_SMBDMATDL 0x8c /* DMA Transmit Data Level */ +#define JZ_SMBDMARDL 0x90 /* DMA Receive Data Level */ +#define JZ_SMBSDASU 0x94 /* SMB SDA Setup Register */ +#define JZ_SMBACKGC 0x98 /* SMB ACK General Call Register */ +#define JZ_SMBENBST 0x9C /* SMB Enable Status Register */ +#define JZ_SMBSDAHD 0xD0 /* SMB SDA HolD time Register */ + #define JZ_HDENB 0x100 /* enable hold time */ + +/* SD/MMC hosts */ +#define JZ_MSC0_BASE 0x13450000 +#define JZ_MSC1_BASE 0x13460000 +#define JZ_MSC2_BASE 0x13470000 + +#define JZ_MSC_CTRL 0x00 + #define JZ_SEND_CCSD 0x8000 + #define JZ_SEND_AS_CCSD 0x4000 + #define JZ_EXIT_MULTIPLE 0x0080 + #define JZ_EXIT_TRANSFER 0x0040 + #define JZ_START_READWAIT 0x0020 + #define JZ_STOP_READWAIT 0x0010 + #define JZ_RESET 0x0008 + #define JZ_START_OP 0x0004 + #define JZ_CLOCK_CTRL_M 0x0003 + #define JZ_CLOCK_START 0x0002 + #define JZ_CLOCK_STOP 0x0001 +#define JZ_MSC_STAT 0x04 + #define JZ_AUTO_CMD12_DONE 0x80000000 + #define JZ_AUTO_CMD23_DONE 0x40000000 + #define JZ_SVS 0x20000000 + #define JZ_PIN_LEVEL_M 0x1f000000 + #define JZ_BCE 0x00100000 /* boot CRC error */ + #define JZ_BDE 0x00080000 /* boot data end */ + #define JZ_BAE 0x00040000 /* boot acknowledge error */ + #define JZ_BAR 0x00020000 /* boot ack. received */ + #define JZ_DMAEND 0x00010000 + #define JZ_IS_RESETTING 0x00008000 + #define JZ_SDIO_INT_ACTIVE 0x00004000 + #define JZ_PRG_DONE 0x00002000 + #define JZ_DATA_TRAN_DONE 0x00001000 + #define JZ_END_CMD_RES 0x00000800 + #define JZ_DATA_FIFO_AFULL 0x00000400 + #define JZ_IS_READWAIT 0x00000200 + #define JZ_CLK_EN 0x00000100 + #define JZ_DATA_FIFO_FULL 0x00000080 + #define JZ_DATA_FIFO_EMPTY 0x00000040 + #define JZ_CRC_RES_ERR 0x00000020 + #define JZ_CRC_READ_ERR 0x00000010 + #define JZ_CRC_WRITE_ERR_M 0x0000000c + #define JZ_CRC_WRITE_OK 0x00000000 + #define JZ_CRC_CARD_ERR 0x00000004 + #define JZ_CRC_NO_STATUS 0x00000008 + #define JZ_TIME_OUT_RES 0x00000002 + #define JZ_TIME_OUT_READ 0x00000001 +#define JZ_MSC_CLKRT 0x08 + #define JZ_DEV_CLK 0x0 + #define JZ_DEV_CLK_2 0x1 /* DEV_CLK / 2 */ + #define JZ_DEV_CLK_4 0x2 /* DEV_CLK / 4 */ + #define JZ_DEV_CLK_8 0x3 /* DEV_CLK / 8 */ + #define JZ_DEV_CLK_16 0x4 /* DEV_CLK / 16 */ + #define JZ_DEV_CLK_32 0x5 /* DEV_CLK / 32 */ + #define JZ_DEV_CLK_64 0x6 /* DEV_CLK / 64 */ + #define JZ_DEV_CLK_128 0x7 /* DEV_CLK / 128 */ +#define JZ_MSC_CMDAT 0x0c + #define JZ_CCS_EXPECTED 0x80000000 + #define JZ_READ_CEATA 0x40000000 + #define JZ_DIS_BOOT 0x08000000 + #define JZ_ENA_BOOT 0x04000000 + #define JZ_EXP_BOOT_ACK 0x02000000 + #define JZ_BOOT_MODE 0x01000000 + #define JZ_AUTO_CMD23 0x00040000 + #define JZ_SDIO_PRDT 0x00020000 + #define JZ_AUTO_CMD12 0x00010000 + #define JZ_RTRG_M 0x0000c000 /* receive FIFO trigger */ + #define JZ_RTRG_16 0x00000000 /* >= 16 */ + #define JZ_RTRG_32 0x00004000 /* >= 32 */ + #define JZ_RTRG_64 0x00008000 /* >= 64 */ + #define JZ_RTRG_96 0x0000c000 /* >= 96 */ + #define JZ_TTRG_M 0x00003000 /* transmit FIFO trigger */ + #define JZ_TTRG_16 0x00000000 /* >= 16 */ + #define JZ_TTRG_32 0x00001000 /* >= 32 */ + #define JZ_TTRG_64 0x00002000 /* >= 64 */ + #define JZ_TTRG_96 0x00003000 /* >= 96 */ + #define JZ_IO_ABORT 0x00000800 + #define JZ_BUS_WIDTH_M 0x00000600 + #define JZ_BUS_1BIT 0x00000000 + #define JZ_BUS_4BIT 0x00000400 + #define JZ_BUS_8BIT 0x00000600 + #define JZ_INIT 0x00000080 /* send 80 clk init before cmd */ + #define JZ_BUSY 0x00000040 + #define JZ_STREAM 0x00000020 + #define JZ_WRITE 0x00000010 /* read otherwise */ + #define JZ_DATA_EN 0x00000008 + #define JZ_RESPONSE_M 0x00000007 /* response format */ + #define JZ_RES_NONE 0x00000000 + #define JZ_RES_R1 0x00000001 /* R1 and R1b */ + #define JZ_RES_R2 0x00000002 + #define JZ_RES_R3 0x00000003 + #define JZ_RES_R4 0x00000004 + #define JZ_RES_R5 0x00000005 + #define JZ_RES_R6 0x00000006 + #define JZ_RES_R7 0x00000007 +#define JZ_MSC_RESTO 0x10 /* 16bit response timeout in MSC_CLK */ +#define JZ_MSC_RDTO 0x14 /* 32bit read timeout in MSC_CLK */ +#define JZ_MSC_BLKLEN 0x18 /* 16bit block length */ +#define JZ_MSC_NOB 0x1c /* 16bit block counter */ +#define JZ_MSC_SNOB 0x20 /* 16bit successful block counter */ +#define JZ_MSC_IMASK 0x24 /* interrupt mask */ + #define JZ_INT_AUTO_CMD23_DONE 0x40000000 + #define JZ_INT_SVS 0x20000000 + #define JZ_INT_PIN_LEVEL_M 0x1f000000 + #define JZ_INT_BCE 0x00100000 + #define JZ_INT_BDE 0x00080000 + #define JZ_INT_BAE 0x00040000 + #define JZ_INT_BAR 0x00020000 + #define JZ_INT_DMAEND 0x00010000 + #define JZ_INT_AUTO_CMD12_DONE 0x00008000 + #define JZ_INT_DATA_FIFO_FULL 0x00004000 + #define JZ_INT_DATA_FIFO_EMPTY 0x00002000 + #define JZ_INT_CRC_RES_ERR 0x00001000 + #define JZ_INT_CRC_READ_ERR 0x00000800 + #define JZ_INT_CRC_WRITE_ERR 0x00000400 + #define JZ_INT_TIMEOUT_RES 0x00000200 + #define JZ_INT_TIMEOUT_READ 0x00000100 + #define JZ_INT_SDIO 0x00000080 + #define JZ_INT_TXFIFO_WR_REQ 0x00000040 + #define JZ_INT_RXFIFO_RD_REQ 0x00000020 + #define JZ_INT_END_CMD_RES 0x00000004 + #define JZ_INT_PRG_DONE 0x00000002 + #define JZ_INT_DATA_TRAN_DONE 0x00000001 +#define JZ_MSC_IFLG 0x28 /* interrupt flags */ +#define JZ_MSC_CMD 0x2c /* 6bit CMD index */ +#define JZ_MSC_ARG 0x30 /* 32bit argument */ +#define JZ_MSC_RES 0x34 /* 8x16bit response data FIFO */ +#define JZ_MSC_RXFIFO 0x38 +#define JZ_MSC_TXFIFO 0x3c +#define JZ_MSC_LPM 0x40 + #define JZ_DRV_SEL_M 0xc0000000 + #define JZ_FALLING_EDGE 0x00000000 + #define JZ_RISING_1NS 0x40000000 /* 1ns delay */ + #define JZ_RISING_4 0x80000000 /* 1/4 MSC_CLK delay */ + #define JZ_SMP_SEL 0x20000000 /* 1 - rising edge */ + #define JZ_LPM 0x00000001 /* low power mode */ +#define JZ_MSC_DMAC 0x44 + #define JZ_MODE_SEL 0x80 /* 1 - specify transfer length */ + #define JZ_AOFST_M 0x60 /* address offset in bytes */ + #define JZ_AOFST_S 6 /* addrress offset shift */ + #define JZ_ALIGNEN 0x10 /* allow non-32bit-aligned transfers */ + #define JZ_INCR_M 0x0c /* burst type */ + #define JZ_INCR_16 0x00 + #define JZ_INCR_32 0x04 + #define JZ_INCR_64 0x08 + #define JZ_DMASEL 0x02 /* 1 - SoC DMAC, 0 - MSC built-in */ + #define JZ_DMAEN 0x01 /* enable DMA */ +#define JZ_MSC_DMANDA 0x48 /* next descriptor paddr */ +#define JZ_MSC_DMADA 0x4c /* current descriptor */ +#define JZ_MSC_DMALEN 0x50 /* transfer tength */ +#define JZ_MSC_DMACMD 0x54 + #define JZ_DMA_IDI_M 0xff000000 + #define JZ_DMA_ID_M 0x00ff0000 + #define JZ_DMA_AOFST_M 0x00000600 + #define JZ_DMA_ALIGN 0x00000100 + #define JZ_DMA_ENDI 0x00000002 + #define JZ_DMA_LINK 0x00000001 +#define JZ_MSC_CTRL2 0x58 + #define JZ_PIP 0x1f000000 /* 1 - intr trigger on high */ + #define JZ_RST_EN 0x00800000 + #define JZ_STPRM 0x00000010 + #define JZ_SVC 0x00000008 + #define JZ_SMS_M 0x00000007 + #define JZ_SMS_DEF 0x00000000 /* default speed */ + #define JZ_SMS_HIGH 0x00000001 /* high speed */ + #define JZ_SMS_SDR12 0x00000002 + #define JZ_SMS_SDR25 0x00000003 + #define JZ_SMS_SDR50 0x00000004 +#define JZ_MSC_RTCNT 0x5c /* RT FIFO count */ + +/* EFUSE Slave Interface */ +#define JZ_EFUSE 0x134100D0 +#define JZ_EFUCTRL 0x00 + #define JZ_EFUSE_BANK 0x40000000 /* select upper 4KBit */ + #define JZ_EFUSE_ADDR_M 0x3fe00000 /* in bytes */ + #define JZ_EFUSE_ADDR_SHIFT 21 + #define JZ_EFUSE_SIZE_M 0x001f0000 /* in bytes */ + #define JZ_EFUSE_SIZE_SHIFT 16 + #define JZ_EFUSE_PROG 0x00008000 /* enable programming */ + #define JZ_EFUSE_WRITE 0x00000002 /* write enable */ + #define JZ_EFUSE_READ 0x00000001 /* read enable */ +#define JZ_EFUCFG 0x04 + #define JZ_EFUSE_INT_E 0x80000000 /* which IRQ? */ + #define JZ_EFUSE_RD_ADJ_M 0x00f00000 + #define JZ_EFUSE_RD_STROBE 0x000f0000 + #define JZ_EFUSE_WR_ADJUST 0x0000f000 + #define JZ_EFUSE_WR_STROBE 0x00000fff +#define JZ_EFUSTATE 0x08 + #define JZ_EFUSE_GLOBAL_P 0x00008000 /* wr protect bits */ + #define JZ_EFUSE_CHIPID_P 0x00004000 + #define JZ_EFUSE_CUSTID_P 0x00002000 + #define JZ_EFUSE_SECWR_EN 0x00001000 + #define JZ_EFUSE_PC_P 0x00000800 + #define JZ_EFUSE_HDMIKEY_P 0x00000400 + #define JZ_EFUSE_SECKEY_P 0x00000200 + #define JZ_EFUSE_SECBOOT_EN 0x00000100 + #define JZ_EFUSE_HDMI_BUSY 0x00000004 + #define JZ_EFUSE_WR_DONE 0x00000002 + #define JZ_EFUSE_RD_DONE 0x00000001 +#define JZ_EFUDATA0 0x0C +#define JZ_EFUDATA1 0x10 +#define JZ_EFUDATA2 0x14 +#define JZ_EFUDATA3 0x18 +#define JZ_EFUDATA4 0x1C +#define JZ_EFUDATA5 0x20 +#define JZ_EFUDATA6 0x24 +#define JZ_EFUDATA7 0x28 + +/* NEMC */ +#define JZ_NEMC_BASE 0x13410000 +#define JZ_NEMC_SMCR(n) (0x10 + (n) * 4) + +# define JZ_NEMC_SMCR_SMT_SHIFT 0 +# define JZ_NEMC_SMCR_SMT_WIDTH 1 +# define JZ_NEMC_SMCR_SMT_MASK (((1 << JZ_NEMC_SMCR_SMT_WIDTH) - 1) << JZ_NEMC_SMCR_SMT_SHIFT) +# define JZ_NEMC_SMCR_SMT_NORMAL (0 << JZ_NEMC_SMCR_SMT_SHIFT) +# define JZ_NEMC_SMCR_SMT_BROM (1 << JZ_NEMC_SMCR_SMT_SHIFT) + +# define JZ_NEMC_SMCR_BL_SHIFT 1 +# define JZ_NEMC_SMCR_BL_WIDTH 2 +# define JZ_NEMC_SMCR_BL_MASK (((1 << JZ_NEMC_SMCR_BL_WIDTH) - 1) << JZ_NEMC_SMCR_BL_SHIFT) +# define JZ_NEMC_SMCR_BL(n) (((n) << JZ_NEMC_SMCR_BL_SHIFT) + +# define JZ_NEMC_SMCR_BW_SHIFT 6 +# define JZ_NEMC_SMCR_BW_WIDTH 2 +# define JZ_NEMC_SMCR_BW_MASK (((1 << JZ_NEMC_SMCR_BW_WIDTH) - 1) << JZ_NEMC_SMCR_BW_SHIFT) +# define JZ_NEMC_SMCR_BW_8 (0 << JZ_NEMC_SMCR_BW_SHIFT) + +# define JZ_NEMC_SMCR_TAS_SHIFT 8 +# define JZ_NEMC_SMCR_TAS_WIDTH 4 +# define JZ_NEMC_SMCR_TAS_MASK (((1 << JZ_NEMC_SMCR_TAS_WIDTH) - 1) << JZ_NEMC_SMCR_TAS_SHIFT) + +# define JZ_NEMC_SMCR_TAH_SHIFT 12 +# define JZ_NEMC_SMCR_TAH_WIDTH 4 +# define JZ_NEMC_SMCR_TAH_MASK (((1 << JZ_NEMC_SMCR_TAH_WIDTH) - 1) << JZ_NEMC_SMCR_TAH_SHIFT) + +# define JZ_NEMC_SMCR_TBP_SHIFT 16 +# define JZ_NEMC_SMCR_TBP_WIDTH 4 +# define JZ_NEMC_SMCR_TBP_MASK (((1 << JZ_NEMC_SMCR_TBP_WIDTH) - 1) << JZ_NEMC_SMCR_TBP_SHIFT) + +# define JZ_NEMC_SMCR_TAW_SHIFT 20 +# define JZ_NEMC_SMCR_TAW_WIDTH 4 +# define JZ_NEMC_SMCR_TAW_MASK (((1 << JZ_NEMC_SMCR_TAW_WIDTH) - 1) << JZ_NEMC_SMCR_TAW_SHIFT) + +# define JZ_NEMC_SMCR_STRV_SHIFT 24 +# define JZ_NEMC_SMCR_STRV_WIDTH 4 +# define JZ_NEMC_SMCR_STRV_MASK (((1 << JZ_NEMC_SMCR_STRV_WIDTH) - 1) << JZ_NEMC_SMCR_STRV_SHIFT) + +#define JZ_NEMC_SACR(n) (0x30 + (n) * 4) + +# define JZ_NEMC_SACR_MASK_SHIFT 0 +# define JZ_NEMC_SACR_MASK_WIDTH 8 +# define JZ_NEMC_SACR_MASK_MASK (((1 << JZ_NEMC_SACR_MASK_WIDTH) - 1) << JZ_NEMC_SACR_MASK_SHIFT) + +# define JZ_NEMC_SACR_ADDR_SHIFT 0 +# define JZ_NEMC_SACR_ADDR_WIDTH 8 +# define JZ_NEMC_SACR_ADDR_MASK (((1 << JZ_NEMC_SACR_ADDR_WIDTH) - 1) << JZ_NEMC_SACR_ADDR_SHIFT) + +#define JC_NEMC_NFSCR 0x50 + +#endif /* JZ4780_REGS_H */ Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_regs.h ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_timer.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_timer.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_timer.c (revision 308868) @@ -0,0 +1,337 @@ +/*- + * Copyright 2013-2015 Alexander Kabaev + * Copyright 2013-2015 John Wehle + * 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 +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include + +#include +#include +#include + +#include + +struct jz4780_timer_softc { + device_t dev; + struct resource * res[4]; + void * ih_cookie; + struct eventtimer et; + struct timecounter tc; +}; + +static struct resource_spec jz4780_timer_spec[] = { + { SYS_RES_MEMORY, 0, RF_ACTIVE }, + { SYS_RES_IRQ, 0, RF_ACTIVE }, /* OST */ + { SYS_RES_IRQ, 1, RF_ACTIVE }, /* TC5 */ + { SYS_RES_IRQ, 2, RF_ACTIVE }, /* TC0-4,6 */ + { -1, 0 } +}; + +/* + * devclass_get_device / device_get_softc could be used + * to dynamically locate this, however the timers are a + * required device which can't be unloaded so there's + * no need for the overhead. + */ +static struct jz4780_timer_softc *jz4780_timer_sc = NULL; + +#define CSR_WRITE_4(sc, reg, val) bus_write_4((sc)->res[0], reg, (val)) +#define CSR_READ_4(sc, reg) bus_read_4((sc)->res[0], reg) + +static unsigned +jz4780_get_timecount(struct timecounter *tc) +{ + struct jz4780_timer_softc *sc = + (struct jz4780_timer_softc *)tc->tc_priv; + + return CSR_READ_4(sc, JZ_OST_CNT_LO); +} + +static int +jz4780_hardclock(void *arg) +{ + struct jz4780_timer_softc *sc = (struct jz4780_timer_softc *)arg; + + CSR_WRITE_4(sc, JZ_TC_TFCR, TFR_FFLAG5); + CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST5); + + if (sc->et.et_active) + sc->et.et_event_cb(&sc->et, sc->et.et_arg); + + return (FILTER_HANDLED); +} + +static int +jz4780_timer_start(struct eventtimer *et, sbintime_t first, sbintime_t period) +{ + struct jz4780_timer_softc *sc = + (struct jz4780_timer_softc *)et->et_priv; + uint32_t ticks; + + ticks = (first * et->et_frequency) / SBT_1S; + if (ticks == 0) + return (EINVAL); + + CSR_WRITE_4(sc, JZ_TC_TDFR(5), ticks); + CSR_WRITE_4(sc, JZ_TC_TCNT(5), 0); + CSR_WRITE_4(sc, JZ_TC_TESR, TESR_TCST5); + + return (0); +} + +static int +jz4780_timer_stop(struct eventtimer *et) +{ + struct jz4780_timer_softc *sc = + (struct jz4780_timer_softc *)et->et_priv; + + CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST5); + return (0); +} + +static int +jz4780_timer_probe(device_t dev) +{ + + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + + if (!ofw_bus_is_compatible(dev, "ingenic,jz4780-tcu")) + return (ENXIO); + + device_set_desc(dev, "Ingenic JZ4780 timer"); + + return (BUS_PROBE_DEFAULT); +} + +static int +jz4780_timer_attach(device_t dev) +{ + struct jz4780_timer_softc *sc = device_get_softc(dev); + pcell_t counter_freq; + clk_t clk; + + /* There should be exactly one instance. */ + if (jz4780_timer_sc != NULL) + return (ENXIO); + + sc->dev = dev; + + if (bus_alloc_resources(dev, jz4780_timer_spec, sc->res)) { + device_printf(dev, "can not allocate resources for device\n"); + return (ENXIO); + } + + counter_freq = 0; + if (clk_get_by_name(dev, "ext", &clk) == 0) { + uint64_t clk_freq; + + if (clk_get_freq(clk, &clk_freq) == 0) + counter_freq = (uint32_t)clk_freq / 16; + clk_release(clk); + } + if (counter_freq == 0) { + device_printf(dev, "unable to determine ext clock frequency\n"); + /* Hardcode value we 'know' is correct */ + counter_freq = 48000000 / 16; + } + + /* + * Disable the timers, select the input for each timer, + * clear and then start OST. + */ + + /* Stop OST, if it happens to be running */ + CSR_WRITE_4(sc, JZ_TC_TECR, TESR_OST); + /* Stop all other channels as well */ + CSR_WRITE_4(sc, JZ_TC_TECR, TESR_TCST0 | TESR_TCST1 | TESR_TCST2 | + TESR_TCST3 | TESR_TCST4 | TESR_TCST5 | TESR_TCST6 | TESR_TCST3); + /* Clear detect mask flags */ + CSR_WRITE_4(sc, JZ_TC_TFCR, 0xFFFFFFFF); + /* Mask all interrupts */ + CSR_WRITE_4(sc, JZ_TC_TMSR, 0xFFFFFFFF); + + /* Init counter with known data */ + CSR_WRITE_4(sc, JZ_OST_CTRL, 0); + CSR_WRITE_4(sc, JZ_OST_CNT_LO, 0); + CSR_WRITE_4(sc, JZ_OST_CNT_HI, 0); + CSR_WRITE_4(sc, JZ_OST_DATA, 0xffffffff); + + /* Configure counter for external clock */ + CSR_WRITE_4(sc, JZ_OST_CTRL, OSTC_EXT_EN | OSTC_MODE | OSTC_DIV_16); + + /* Start the counter again */ + CSR_WRITE_4(sc, JZ_TC_TESR, TESR_OST); + + /* Configure TCU channel 5 similarly to OST and leave it disabled */ + CSR_WRITE_4(sc, JZ_TC_TCSR(5), TCSR_EXT_EN | TCSR_DIV_16); + CSR_WRITE_4(sc, JZ_TC_TMCR, TMR_FMASK(5)); + + if (bus_setup_intr(dev, sc->res[2], INTR_TYPE_CLK, + jz4780_hardclock, NULL, sc, &sc->ih_cookie)) { + device_printf(dev, "could not setup interrupt handler\n"); + bus_release_resources(dev, jz4780_timer_spec, sc->res); + return (ENXIO); + } + + sc->et.et_name = "JZ4780 TCU5"; + sc->et.et_flags = ET_FLAGS_ONESHOT; + sc->et.et_frequency = counter_freq; + sc->et.et_quality = 1000; + sc->et.et_min_period = (0x00000002LLU * SBT_1S) / sc->et.et_frequency; + sc->et.et_max_period = (0x0000fffeLLU * SBT_1S) / sc->et.et_frequency; + sc->et.et_start = jz4780_timer_start; + sc->et.et_stop = jz4780_timer_stop; + sc->et.et_priv = sc; + + et_register(&sc->et); + + sc->tc.tc_get_timecount = jz4780_get_timecount; + sc->tc.tc_name = "JZ4780 OST"; + sc->tc.tc_frequency = counter_freq; + sc->tc.tc_counter_mask = ~0u; + sc->tc.tc_quality = 1000; + sc->tc.tc_priv = sc; + + tc_init(&sc->tc); + + /* Now when tc is initialized, allow DELAY to find it */ + jz4780_timer_sc = sc; + + return (0); +} + +static int +jz4780_timer_detach(device_t dev) +{ + + return (EBUSY); +} + +static device_method_t jz4780_timer_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_timer_probe), + DEVMETHOD(device_attach, jz4780_timer_attach), + DEVMETHOD(device_detach, jz4780_timer_detach), + + DEVMETHOD_END +}; + +static driver_t jz4780_timer_driver = { + "timer", + jz4780_timer_methods, + sizeof(struct jz4780_timer_softc), +}; + +static devclass_t jz4780_timer_devclass; + +EARLY_DRIVER_MODULE(timer, simplebus, jz4780_timer_driver, + jz4780_timer_devclass, 0, 0, BUS_PASS_TIMER); + +void +DELAY(int usec) +{ + uint32_t counter; + uint32_t delta, now, previous, remaining; + + /* Timer has not yet been initialized */ + if (jz4780_timer_sc == NULL) { + for (; usec > 0; usec--) + for (counter = 200; counter > 0; counter--) { + /* Prevent gcc from optimizing out the loop */ + mips_rd_cause(); + } + return; + } + + /* + * Some of the other timers in the source tree do this calculation as: + * + * usec * ((sc->tc.tc_frequency / 1000000) + 1) + * + * which gives a fairly pessimistic result when tc_frequency is an exact + * multiple of 1000000. Given the data type and typical values for + * tc_frequency adding 999999 shouldn't overflow. + */ + remaining = usec * ((jz4780_timer_sc->tc.tc_frequency + 999999) / + 1000000); + + /* + * We add one since the first iteration may catch the counter just + * as it is changing. + */ + remaining += 1; + + previous = jz4780_get_timecount(&jz4780_timer_sc->tc); + + for ( ; ; ) { + now = jz4780_get_timecount(&jz4780_timer_sc->tc); + + /* + * If the timer has rolled over, then we have the case: + * + * if (previous > now) { + * delta = (0 - previous) + now + * } + * + * which is really no different then the normal case. + * Both cases are simply: + * + * delta = now - previous. + */ + delta = now - previous; + + if (delta >= remaining) + break; + + previous = now; + remaining -= delta; + } +} + +void +platform_initclocks(void) +{ + +} + Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_timer.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/ingenic/jz4780_uart.c =================================================================== --- projects/clang390-import/sys/mips/ingenic/jz4780_uart.c (nonexistent) +++ projects/clang390-import/sys/mips/ingenic/jz4780_uart.c (revision 308868) @@ -0,0 +1,220 @@ +/*- + * Copyright (c) 2013 Ian Lepore + * 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 ``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 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 "opt_platform.h" + +#include +__FBSDID("$FreeBSD$"); + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "uart_if.h" + +/* + * High-level UART interface. + */ +struct jz4780_uart_softc { + struct ns8250_softc ns8250_base; + clk_t clk_mod; + clk_t clk_baud; +}; + +static int +jz4780_bus_attach(struct uart_softc *sc) +{ + struct ns8250_softc *ns8250; + struct uart_bas *bas; + int rv; + + ns8250 = (struct ns8250_softc *)sc; + bas = &sc->sc_bas; + + rv = ns8250_bus_attach(sc); + if (rv != 0) + return (0); + + /* Configure uart to use extra IER_RXTMOUT bit */ + ns8250->ier_rxbits = IER_RXTMOUT | IER_EMSC | IER_ERLS | IER_ERXRDY; + ns8250->ier_mask = ~(ns8250->ier_rxbits); + ns8250->ier = uart_getreg(bas, REG_IER) & ns8250->ier_mask; + ns8250->ier |= ns8250->ier_rxbits; + uart_setreg(bas, REG_IER, ns8250->ier); + uart_barrier(bas); + return (0); +} + +static kobj_method_t jz4780_uart_methods[] = { + KOBJMETHOD(uart_probe, ns8250_bus_probe), + KOBJMETHOD(uart_attach, jz4780_bus_attach), + KOBJMETHOD(uart_detach, ns8250_bus_detach), + KOBJMETHOD(uart_flush, ns8250_bus_flush), + KOBJMETHOD(uart_getsig, ns8250_bus_getsig), + KOBJMETHOD(uart_ioctl, ns8250_bus_ioctl), + KOBJMETHOD(uart_ipend, ns8250_bus_ipend), + KOBJMETHOD(uart_param, ns8250_bus_param), + KOBJMETHOD(uart_receive, ns8250_bus_receive), + KOBJMETHOD(uart_setsig, ns8250_bus_setsig), + KOBJMETHOD(uart_transmit, ns8250_bus_transmit), + KOBJMETHOD(uart_grab, ns8250_bus_grab), + KOBJMETHOD(uart_ungrab, ns8250_bus_ungrab), + KOBJMETHOD_END +}; + +static struct uart_class jz4780_uart_class = { + "jz4780_uart_class", + jz4780_uart_methods, + sizeof(struct jz4780_uart_softc), + .uc_ops = &uart_ns8250_ops, + .uc_range = 8, + .uc_rclk = 0, +}; + +/* Compatible devices. */ +static struct ofw_compat_data compat_data[] = { + {"ingenic,jz4780-uart", (uintptr_t)&jz4780_uart_class}, + {NULL, (uintptr_t)NULL}, +}; + +UART_FDT_CLASS(compat_data); + +/* + * UART Driver interface. + */ +static int +jz4780_uart_get_shift(device_t dev) +{ + phandle_t node; + pcell_t shift; + + node = ofw_bus_get_node(dev); + if ((OF_getencprop(node, "reg-shift", &shift, sizeof(shift))) <= 0) + shift = 2; + return ((int)shift); +} + +static int +jz4780_uart_probe(device_t dev) +{ + struct jz4780_uart_softc *sc; + uint64_t freq; + int shift; + int rv; + const struct ofw_compat_data *cd; + + sc = device_get_softc(dev); + if (!ofw_bus_status_okay(dev)) + return (ENXIO); + cd = ofw_bus_search_compatible(dev, compat_data); + if (cd->ocd_data == 0) + return (ENXIO); + + /* Figure out clock setup */ + rv = clk_get_by_ofw_name(dev, 0, "module", &sc->clk_mod); + if (rv != 0) { + device_printf(dev, "Cannot get UART clock: %d\n", rv); + return (ENXIO); + } + rv = clk_enable(sc->clk_mod); + if (rv != 0) { + device_printf(dev, "Cannot enable UART clock: %d\n", rv); + return (ENXIO); + } + rv = clk_get_by_ofw_name(dev, 0, "baud", &sc->clk_baud); + if (rv != 0) { + device_printf(dev, "Cannot get UART clock: %d\n", rv); + return (ENXIO); + } + rv = clk_enable(sc->clk_baud); + if (rv != 0) { + device_printf(dev, "Cannot enable UART clock: %d\n", rv); + return (ENXIO); + } + rv = clk_get_freq(sc->clk_baud, &freq); + if (rv != 0) { + device_printf(dev, "Cannot determine UART clock frequency: %d\n", rv); + return (ENXIO); + } + + if (bootverbose) + device_printf(dev, "got UART clock: %lld\n", freq); + sc->ns8250_base.base.sc_class = (struct uart_class *)cd->ocd_data; + shift = jz4780_uart_get_shift(dev); + return (uart_bus_probe(dev, shift, (int)freq, 0, 0)); +} + +static int +jz4780_uart_detach(device_t dev) +{ + struct jz4780_uart_softc *sc; + int rv; + + rv = uart_bus_detach(dev); + if (rv != 0) + return (rv); + + sc = device_get_softc(dev); + if (sc->clk_mod != NULL) { + clk_release(sc->clk_mod); + } + if (sc->clk_baud != NULL) { + clk_release(sc->clk_baud); + } + return (0); +} + +static device_method_t jz4780_uart_bus_methods[] = { + /* Device interface */ + DEVMETHOD(device_probe, jz4780_uart_probe), + DEVMETHOD(device_attach, uart_bus_attach), + DEVMETHOD(device_detach, jz4780_uart_detach), + { 0, 0 } +}; + +static driver_t jz4780_uart_driver = { + uart_driver_name, + jz4780_uart_bus_methods, + sizeof(struct jz4780_uart_softc), +}; + +DRIVER_MODULE(jz4780_uart, simplebus, jz4780_uart_driver, uart_devclass, + 0, 0); Property changes on: projects/clang390-import/sys/mips/ingenic/jz4780_uart.c ___________________________________________________________________ Added: svn:eol-style ## -0,0 +1 ## +native \ No newline at end of property Added: svn:keywords ## -0,0 +1 ## +FreeBSD=%H \ No newline at end of property Added: svn:mime-type ## -0,0 +1 ## +text/plain \ No newline at end of property Index: projects/clang390-import/sys/mips/mediatek/files.mediatek =================================================================== --- projects/clang390-import/sys/mips/mediatek/files.mediatek (revision 308867) +++ projects/clang390-import/sys/mips/mediatek/files.mediatek (revision 308868) @@ -1,47 +1,39 @@ # $FreeBSD$ mips/mediatek/mtk_machdep.c standard mips/mediatek/mtk_sysctl.c standard mips/mediatek/mtk_soc.c standard mips/mediatek/mtk_reset.c standard mips/mediatek/mtk_clock.c standard mips/mediatek/mtk_pinctrl.c standard mips/mediatek/palmbus.c standard mips/mediatek/mtk_intr_v1.c optional mtk_intr_v1 mips/mediatek/mtk_intr_v2.c optional mtk_intr_v2 mips/mediatek/mtk_intr_gic.c optional mtk_intr_gic mips/mediatek/uart_dev_mtk.c optional uart uart_dev_mtk mips/mediatek/mtk_spi_v1.c optional spibus mtk_spi_v1 mips/mediatek/mtk_spi_v2.c optional spibus mtk_spi_v2 mips/mediatek/mtk_usb_phy.c optional usb mtk_usb_phy mips/mediatek/mtk_xhci.c optional usb xhci mips/mediatek/mtk_ohci.c optional usb ohci mips/mediatek/mtk_ehci.c optional usb ehci mips/mediatek/mtk_dotg.c optional usb dwcotg mips/mediatek/mtk_pcie.c optional pci mips/mediatek/mtk_gpio_v1.c optional gpio mtk_gpio_v1 mips/mediatek/mtk_gpio_v2.c optional gpio mtk_gpio_v2 #mips/mediatek/mtk_mmc.c optional mmc # Ralink/Mediatek Ethernet driver dev/rt/if_rt.c optional rt -# Hack to reuse ARM intrng code -kern/subr_intr.c standard -kern/msi_if.m standard -kern/pic_if.m standard - -# Intrng compatible MIPS32 interrupt controller -mips/mips/mips_pic.c standard - # Standard MIPS ticker mips/mips/tick.c standard # Temporary Reset if mips/mediatek/fdt_reset.c standard mips/mediatek/fdt_reset_if.m standard # Switch dev/etherswitch/mtkswitch/mtkswitch.c optional mtkswitch dev/etherswitch/mtkswitch/mtkswitch_rt3050.c optional mtkswitch dev/etherswitch/mtkswitch/mtkswitch_mt7620.c optional mtkswitch Index: projects/clang390-import/sys/mips/mips/busdma_machdep.c =================================================================== --- projects/clang390-import/sys/mips/mips/busdma_machdep.c (revision 308867) +++ projects/clang390-import/sys/mips/mips/busdma_machdep.c (revision 308868) @@ -1,1493 +1,1493 @@ /*- * Copyright (c) 2006 Oleksandr Tymoshenko * 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, immediately at the beginning of the file. * 2. The name of the author may not be used to endorse or promote products * derived from this software without specific prior written permission. * * 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. * * From i386/busdma_machdep.c,v 1.26 2002/04/19 22:58:09 alfred */ #include __FBSDID("$FreeBSD$"); /* * MIPS bus dma support routines */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #define MAX_BPAGES 64 #define BUS_DMA_COULD_BOUNCE BUS_DMA_BUS3 #define BUS_DMA_MIN_ALLOC_COMP BUS_DMA_BUS4 struct bounce_zone; struct bus_dma_tag { bus_dma_tag_t parent; bus_size_t alignment; bus_addr_t boundary; bus_addr_t lowaddr; bus_addr_t highaddr; bus_dma_filter_t *filter; void *filterarg; bus_size_t maxsize; u_int nsegments; bus_size_t maxsegsz; int flags; int ref_count; int map_count; bus_dma_lock_t *lockfunc; void *lockfuncarg; bus_dma_segment_t *segments; struct bounce_zone *bounce_zone; }; struct bounce_page { vm_offset_t vaddr; /* kva of bounce buffer */ vm_offset_t vaddr_nocache; /* kva of bounce buffer uncached */ bus_addr_t busaddr; /* Physical address */ vm_offset_t datavaddr; /* kva of client data */ bus_addr_t dataaddr; /* client physical address */ bus_size_t datacount; /* client data count */ STAILQ_ENTRY(bounce_page) links; }; struct sync_list { vm_offset_t vaddr; /* kva of bounce buffer */ bus_addr_t busaddr; /* Physical address */ bus_size_t datacount; /* client data count */ }; int busdma_swi_pending; struct bounce_zone { STAILQ_ENTRY(bounce_zone) links; STAILQ_HEAD(bp_list, bounce_page) bounce_page_list; int total_bpages; int free_bpages; int reserved_bpages; int active_bpages; int total_bounced; int total_deferred; int map_count; bus_size_t alignment; bus_addr_t lowaddr; char zoneid[8]; char lowaddrid[20]; struct sysctl_ctx_list sysctl_tree; struct sysctl_oid *sysctl_tree_top; }; static struct mtx bounce_lock; static int total_bpages; static int busdma_zonecount; static STAILQ_HEAD(, bounce_zone) bounce_zone_list; static SYSCTL_NODE(_hw, OID_AUTO, busdma, CTLFLAG_RD, 0, "Busdma parameters"); SYSCTL_INT(_hw_busdma, OID_AUTO, total_bpages, CTLFLAG_RD, &total_bpages, 0, "Total bounce pages"); #define DMAMAP_UNCACHEABLE 0x08 #define DMAMAP_CACHE_ALIGNED 0x10 struct bus_dmamap { struct bp_list bpages; int pagesneeded; int pagesreserved; bus_dma_tag_t dmat; struct memdesc mem; int flags; void *origbuffer; void *allocbuffer; TAILQ_ENTRY(bus_dmamap) freelist; STAILQ_ENTRY(bus_dmamap) links; bus_dmamap_callback_t *callback; void *callback_arg; int sync_count; struct sync_list *slist; }; static STAILQ_HEAD(, bus_dmamap) bounce_map_waitinglist; static STAILQ_HEAD(, bus_dmamap) bounce_map_callbacklist; static void init_bounce_pages(void *dummy); static int alloc_bounce_zone(bus_dma_tag_t dmat); static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages); static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit); static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr, bus_addr_t addr, bus_size_t size); static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage); /* Default tag, as most drivers provide no parent tag. */ bus_dma_tag_t mips_root_dma_tag; static uma_zone_t dmamap_zone; /* Cache of struct bus_dmamap items */ static busdma_bufalloc_t coherent_allocator; /* Cache of coherent buffers */ static busdma_bufalloc_t standard_allocator; /* Cache of standard buffers */ MALLOC_DEFINE(M_BUSDMA, "busdma", "busdma metadata"); MALLOC_DEFINE(M_BOUNCE, "bounce", "busdma bounce pages"); /* * This is the ctor function passed to uma_zcreate() for the pool of dma maps. * It'll need platform-specific changes if this code is copied. */ static int dmamap_ctor(void *mem, int size, void *arg, int flags) { bus_dmamap_t map; bus_dma_tag_t dmat; map = (bus_dmamap_t)mem; dmat = (bus_dma_tag_t)arg; dmat->map_count++; map->dmat = dmat; map->flags = 0; map->slist = NULL; map->allocbuffer = NULL; map->sync_count = 0; STAILQ_INIT(&map->bpages); return (0); } /* * This is the dtor function passed to uma_zcreate() for the pool of dma maps. * It may need platform-specific changes if this code is copied . */ static void dmamap_dtor(void *mem, int size, void *arg) { bus_dmamap_t map; map = (bus_dmamap_t)mem; map->dmat->map_count--; } static void busdma_init(void *dummy) { /* Create a cache of maps for bus_dmamap_create(). */ dmamap_zone = uma_zcreate("dma maps", sizeof(struct bus_dmamap), dmamap_ctor, dmamap_dtor, NULL, NULL, UMA_ALIGN_PTR, 0); /* Create a cache of buffers in standard (cacheable) memory. */ standard_allocator = busdma_bufalloc_create("buffer", - mips_pdcache_linesize, /* minimum_alignment */ + mips_dcache_max_linesize, /* minimum_alignment */ NULL, /* uma_alloc func */ NULL, /* uma_free func */ 0); /* uma_zcreate_flags */ /* * Create a cache of buffers in uncacheable memory, to implement the * BUS_DMA_COHERENT flag. */ coherent_allocator = busdma_bufalloc_create("coherent", - mips_pdcache_linesize, /* minimum_alignment */ + mips_dcache_max_linesize, /* minimum_alignment */ busdma_bufalloc_alloc_uncacheable, busdma_bufalloc_free_uncacheable, 0); /* uma_zcreate_flags */ } SYSINIT(busdma, SI_SUB_KMEM, SI_ORDER_FOURTH, busdma_init, NULL); /* * Return true if a match is made. * * To find a match walk the chain of bus_dma_tag_t's looking for 'paddr'. * * If paddr is within the bounds of the dma tag then call the filter callback * to check for a match, if there is no filter callback then assume a match. */ static int run_filter(bus_dma_tag_t dmat, bus_addr_t paddr) { int retval; retval = 0; do { if (((paddr > dmat->lowaddr && paddr <= dmat->highaddr) || ((paddr & (dmat->alignment - 1)) != 0)) && (dmat->filter == NULL || (*dmat->filter)(dmat->filterarg, paddr) != 0)) retval = 1; dmat = dmat->parent; } while (retval == 0 && dmat != NULL); return (retval); } /* * Check to see if the specified page is in an allowed DMA range. */ static __inline int _bus_dma_can_bounce(vm_offset_t lowaddr, vm_offset_t highaddr) { int i; for (i = 0; phys_avail[i] && phys_avail[i + 1]; i += 2) { if ((lowaddr >= phys_avail[i] && lowaddr <= phys_avail[i + 1]) || (lowaddr < phys_avail[i] && highaddr > phys_avail[i])) return (1); } return (0); } /* * Convenience function for manipulating driver locks from busdma (during * busdma_swi, for example). Drivers that don't provide their own locks * should specify &Giant to dmat->lockfuncarg. Drivers that use their own * non-mutex locking scheme don't have to use this at all. */ void busdma_lock_mutex(void *arg, bus_dma_lock_op_t op) { struct mtx *dmtx; dmtx = (struct mtx *)arg; switch (op) { case BUS_DMA_LOCK: mtx_lock(dmtx); break; case BUS_DMA_UNLOCK: mtx_unlock(dmtx); break; default: panic("Unknown operation 0x%x for busdma_lock_mutex!", op); } } /* * dflt_lock should never get called. It gets put into the dma tag when * lockfunc == NULL, which is only valid if the maps that are associated * with the tag are meant to never be defered. * XXX Should have a way to identify which driver is responsible here. */ static void dflt_lock(void *arg, bus_dma_lock_op_t op) { #ifdef INVARIANTS panic("driver error: busdma dflt_lock called"); #else printf("DRIVER_ERROR: busdma dflt_lock called\n"); #endif } static __inline bus_dmamap_t _busdma_alloc_dmamap(bus_dma_tag_t dmat) { struct sync_list *slist; bus_dmamap_t map; slist = malloc(sizeof(*slist) * dmat->nsegments, M_BUSDMA, M_NOWAIT); if (slist == NULL) return (NULL); map = uma_zalloc_arg(dmamap_zone, dmat, M_NOWAIT); if (map != NULL) map->slist = slist; else free(slist, M_BUSDMA); return (map); } static __inline void _busdma_free_dmamap(bus_dmamap_t map) { free(map->slist, M_BUSDMA); uma_zfree(dmamap_zone, map); } /* * Allocate a device specific dma_tag. */ #define SEG_NB 1024 int bus_dma_tag_create(bus_dma_tag_t parent, bus_size_t alignment, bus_addr_t boundary, bus_addr_t lowaddr, bus_addr_t highaddr, bus_dma_filter_t *filter, void *filterarg, bus_size_t maxsize, int nsegments, bus_size_t maxsegsz, int flags, bus_dma_lock_t *lockfunc, void *lockfuncarg, bus_dma_tag_t *dmat) { bus_dma_tag_t newtag; int error = 0; /* Return a NULL tag on failure */ *dmat = NULL; if (!parent) parent = mips_root_dma_tag; newtag = (bus_dma_tag_t)malloc(sizeof(*newtag), M_BUSDMA, M_NOWAIT); if (newtag == NULL) { CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", __func__, newtag, 0, error); return (ENOMEM); } newtag->parent = parent; newtag->alignment = alignment; newtag->boundary = boundary; newtag->lowaddr = trunc_page((vm_offset_t)lowaddr) + (PAGE_SIZE - 1); newtag->highaddr = trunc_page((vm_offset_t)highaddr) + (PAGE_SIZE - 1); newtag->filter = filter; newtag->filterarg = filterarg; newtag->maxsize = maxsize; newtag->nsegments = nsegments; newtag->maxsegsz = maxsegsz; newtag->flags = flags; if (cpuinfo.cache_coherent_dma) newtag->flags |= BUS_DMA_COHERENT; newtag->ref_count = 1; /* Count ourself */ newtag->map_count = 0; if (lockfunc != NULL) { newtag->lockfunc = lockfunc; newtag->lockfuncarg = lockfuncarg; } else { newtag->lockfunc = dflt_lock; newtag->lockfuncarg = NULL; } newtag->segments = NULL; /* * Take into account any restrictions imposed by our parent tag */ if (parent != NULL) { newtag->lowaddr = MIN(parent->lowaddr, newtag->lowaddr); newtag->highaddr = MAX(parent->highaddr, newtag->highaddr); if (newtag->boundary == 0) newtag->boundary = parent->boundary; else if (parent->boundary != 0) newtag->boundary = MIN(parent->boundary, newtag->boundary); if ((newtag->filter != NULL) || ((parent->flags & BUS_DMA_COULD_BOUNCE) != 0)) newtag->flags |= BUS_DMA_COULD_BOUNCE; if (newtag->filter == NULL) { /* * Short circuit looking at our parent directly * since we have encapsulated all of its information */ newtag->filter = parent->filter; newtag->filterarg = parent->filterarg; newtag->parent = parent->parent; } if (newtag->parent != NULL) atomic_add_int(&parent->ref_count, 1); } if (_bus_dma_can_bounce(newtag->lowaddr, newtag->highaddr) || newtag->alignment > 1) newtag->flags |= BUS_DMA_COULD_BOUNCE; if (((newtag->flags & BUS_DMA_COULD_BOUNCE) != 0) && (flags & BUS_DMA_ALLOCNOW) != 0) { struct bounce_zone *bz; /* Must bounce */ if ((error = alloc_bounce_zone(newtag)) != 0) { free(newtag, M_BUSDMA); return (error); } bz = newtag->bounce_zone; if (ptoa(bz->total_bpages) < maxsize) { int pages; pages = atop(maxsize) - bz->total_bpages; /* Add pages to our bounce pool */ if (alloc_bounce_pages(newtag, pages) < pages) error = ENOMEM; } /* Performed initial allocation */ newtag->flags |= BUS_DMA_MIN_ALLOC_COMP; } else newtag->bounce_zone = NULL; if (error != 0) free(newtag, M_BUSDMA); else *dmat = newtag; CTR4(KTR_BUSDMA, "%s returned tag %p tag flags 0x%x error %d", __func__, newtag, (newtag != NULL ? newtag->flags : 0), error); return (error); } int bus_dma_tag_destroy(bus_dma_tag_t dmat) { #ifdef KTR bus_dma_tag_t dmat_copy = dmat; #endif if (dmat != NULL) { if (dmat->map_count != 0) return (EBUSY); while (dmat != NULL) { bus_dma_tag_t parent; parent = dmat->parent; atomic_subtract_int(&dmat->ref_count, 1); if (dmat->ref_count == 0) { if (dmat->segments != NULL) free(dmat->segments, M_BUSDMA); free(dmat, M_BUSDMA); /* * Last reference count, so * release our reference * count on our parent. */ dmat = parent; } else dmat = NULL; } } CTR2(KTR_BUSDMA, "%s tag %p", __func__, dmat_copy); return (0); } #include /* * Allocate a handle for mapping from kva/uva/physical * address space into bus device space. */ int bus_dmamap_create(bus_dma_tag_t dmat, int flags, bus_dmamap_t *mapp) { bus_dmamap_t newmap; int error = 0; if (dmat->segments == NULL) { dmat->segments = (bus_dma_segment_t *)malloc( sizeof(bus_dma_segment_t) * dmat->nsegments, M_BUSDMA, M_NOWAIT); if (dmat->segments == NULL) { CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM); return (ENOMEM); } } newmap = _busdma_alloc_dmamap(dmat); if (newmap == NULL) { CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, ENOMEM); return (ENOMEM); } *mapp = newmap; /* * Bouncing might be required if the driver asks for an active * exclusion region, a data alignment that is stricter than 1, and/or * an active address boundary. */ if (dmat->flags & BUS_DMA_COULD_BOUNCE) { /* Must bounce */ struct bounce_zone *bz; int maxpages; if (dmat->bounce_zone == NULL) { if ((error = alloc_bounce_zone(dmat)) != 0) { _busdma_free_dmamap(newmap); *mapp = NULL; return (error); } } bz = dmat->bounce_zone; /* Initialize the new map */ STAILQ_INIT(&((*mapp)->bpages)); /* * Attempt to add pages to our pool on a per-instance * basis up to a sane limit. */ maxpages = MAX_BPAGES; if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0 || (bz->map_count > 0 && bz->total_bpages < maxpages)) { int pages; pages = MAX(atop(dmat->maxsize), 1); pages = MIN(maxpages - bz->total_bpages, pages); pages = MAX(pages, 1); if (alloc_bounce_pages(dmat, pages) < pages) error = ENOMEM; if ((dmat->flags & BUS_DMA_MIN_ALLOC_COMP) == 0) { if (error == 0) dmat->flags |= BUS_DMA_MIN_ALLOC_COMP; } else { error = 0; } } bz->map_count++; } CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", __func__, dmat, dmat->flags, error); return (0); } /* * Destroy a handle for mapping from kva/uva/physical * address space into bus device space. */ int bus_dmamap_destroy(bus_dma_tag_t dmat, bus_dmamap_t map) { if (STAILQ_FIRST(&map->bpages) != NULL || map->sync_count != 0) { CTR3(KTR_BUSDMA, "%s: tag %p error %d", __func__, dmat, EBUSY); return (EBUSY); } if (dmat->bounce_zone) dmat->bounce_zone->map_count--; _busdma_free_dmamap(map); CTR2(KTR_BUSDMA, "%s: tag %p error 0", __func__, dmat); return (0); } /* * Allocate a piece of memory that can be efficiently mapped into * bus device space based on the constraints lited in the dma tag. * A dmamap to for use with dmamap_load is also allocated. */ int bus_dmamem_alloc(bus_dma_tag_t dmat, void** vaddrp, int flags, bus_dmamap_t *mapp) { bus_dmamap_t newmap = NULL; busdma_bufalloc_t ba; struct busdma_bufzone *bufzone; vm_memattr_t memattr; void *vaddr; int mflags; if (flags & BUS_DMA_NOWAIT) mflags = M_NOWAIT; else mflags = M_WAITOK; if (dmat->segments == NULL) { dmat->segments = (bus_dma_segment_t *)malloc( sizeof(bus_dma_segment_t) * dmat->nsegments, M_BUSDMA, mflags); if (dmat->segments == NULL) { CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", __func__, dmat, dmat->flags, ENOMEM); return (ENOMEM); } } newmap = _busdma_alloc_dmamap(dmat); if (newmap == NULL) { CTR4(KTR_BUSDMA, "%s: tag %p tag flags 0x%x error %d", __func__, dmat, dmat->flags, ENOMEM); return (ENOMEM); } /* * If all the memory is coherent with DMA then we don't need to * do anything special for a coherent mapping request. */ if (dmat->flags & BUS_DMA_COHERENT) flags &= ~BUS_DMA_COHERENT; if (flags & BUS_DMA_COHERENT) { memattr = VM_MEMATTR_UNCACHEABLE; ba = coherent_allocator; newmap->flags |= DMAMAP_UNCACHEABLE; } else { memattr = VM_MEMATTR_DEFAULT; ba = standard_allocator; } /* All buffers we allocate are cache-aligned. */ newmap->flags |= DMAMAP_CACHE_ALIGNED; if (flags & BUS_DMA_ZERO) mflags |= M_ZERO; /* * Try to find a bufzone in the allocator that holds a cache of buffers * of the right size for this request. If the buffer is too big to be * held in the allocator cache, this returns NULL. */ bufzone = busdma_bufalloc_findzone(ba, dmat->maxsize); /* * Allocate the buffer from the uma(9) allocator if... * - It's small enough to be in the allocator (bufzone not NULL). * - The alignment constraint isn't larger than the allocation size * (the allocator aligns buffers to their size boundaries). * - There's no need to handle lowaddr/highaddr exclusion zones. * else allocate non-contiguous pages if... * - The page count that could get allocated doesn't exceed nsegments. * - The alignment constraint isn't larger than a page boundary. * - There are no boundary-crossing constraints. * else allocate a block of contiguous pages because one or more of the * constraints is something that only the contig allocator can fulfill. */ if (bufzone != NULL && dmat->alignment <= bufzone->size && !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr)) { vaddr = uma_zalloc(bufzone->umazone, mflags); } else if (dmat->nsegments >= btoc(dmat->maxsize) && dmat->alignment <= PAGE_SIZE && dmat->boundary == 0) { vaddr = (void *)kmem_alloc_attr(kernel_arena, dmat->maxsize, mflags, 0, dmat->lowaddr, memattr); } else { vaddr = (void *)kmem_alloc_contig(kernel_arena, dmat->maxsize, mflags, 0, dmat->lowaddr, dmat->alignment, dmat->boundary, memattr); } if (vaddr == NULL) { _busdma_free_dmamap(newmap); newmap = NULL; } else { newmap->sync_count = 0; } *vaddrp = vaddr; *mapp = newmap; return (vaddr == NULL ? ENOMEM : 0); } /* * Free a piece of memory and it's allocated dmamap, that was allocated * via bus_dmamem_alloc. Make the same choice for free/contigfree. */ void bus_dmamem_free(bus_dma_tag_t dmat, void *vaddr, bus_dmamap_t map) { struct busdma_bufzone *bufzone; busdma_bufalloc_t ba; if (map->flags & DMAMAP_UNCACHEABLE) ba = coherent_allocator; else ba = standard_allocator; free(map->slist, M_BUSDMA); uma_zfree(dmamap_zone, map); bufzone = busdma_bufalloc_findzone(ba, dmat->maxsize); if (bufzone != NULL && dmat->alignment <= bufzone->size && !_bus_dma_can_bounce(dmat->lowaddr, dmat->highaddr)) uma_zfree(bufzone->umazone, vaddr); else kmem_free(kernel_arena, (vm_offset_t)vaddr, dmat->maxsize); CTR3(KTR_BUSDMA, "%s: tag %p flags 0x%x", __func__, dmat, dmat->flags); } static void _bus_dmamap_count_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, bus_size_t buflen, int flags) { bus_addr_t curaddr; bus_size_t sgsize; if ((map->pagesneeded == 0)) { CTR3(KTR_BUSDMA, "lowaddr= %d, boundary= %d, alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment); CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, map->pagesneeded); /* * Count the number of bounce pages * needed in order to complete this transfer */ curaddr = buf; while (buflen != 0) { sgsize = MIN(buflen, dmat->maxsegsz); if (run_filter(dmat, curaddr) != 0) { sgsize = MIN(sgsize, PAGE_SIZE); map->pagesneeded++; } curaddr += sgsize; buflen -= sgsize; } CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); } } static void _bus_dmamap_count_pages(bus_dma_tag_t dmat, bus_dmamap_t map, pmap_t pmap, void *buf, bus_size_t buflen, int flags) { vm_offset_t vaddr; vm_offset_t vendaddr; bus_addr_t paddr; if ((map->pagesneeded == 0)) { CTR3(KTR_BUSDMA, "lowaddr= %d, boundary= %d, alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment); CTR2(KTR_BUSDMA, "map= %p, pagesneeded= %d", map, map->pagesneeded); /* * Count the number of bounce pages * needed in order to complete this transfer */ vaddr = (vm_offset_t)buf; vendaddr = (vm_offset_t)buf + buflen; while (vaddr < vendaddr) { bus_size_t sg_len; KASSERT(kernel_pmap == pmap, ("pmap is not kernel pmap")); sg_len = PAGE_SIZE - ((vm_offset_t)vaddr & PAGE_MASK); paddr = pmap_kextract(vaddr); if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) && run_filter(dmat, paddr) != 0) { sg_len = roundup2(sg_len, dmat->alignment); map->pagesneeded++; } vaddr += sg_len; } CTR1(KTR_BUSDMA, "pagesneeded= %d\n", map->pagesneeded); } } static int _bus_dmamap_reserve_pages(bus_dma_tag_t dmat, bus_dmamap_t map,int flags) { /* Reserve Necessary Bounce Pages */ mtx_lock(&bounce_lock); if (flags & BUS_DMA_NOWAIT) { if (reserve_bounce_pages(dmat, map, 0) != 0) { mtx_unlock(&bounce_lock); return (ENOMEM); } } else { if (reserve_bounce_pages(dmat, map, 1) != 0) { /* Queue us for resources */ STAILQ_INSERT_TAIL(&bounce_map_waitinglist, map, links); mtx_unlock(&bounce_lock); return (EINPROGRESS); } } mtx_unlock(&bounce_lock); return (0); } /* * Add a single contiguous physical range to the segment list. */ static int _bus_dmamap_addseg(bus_dma_tag_t dmat, bus_dmamap_t map, bus_addr_t curaddr, bus_size_t sgsize, bus_dma_segment_t *segs, int *segp) { bus_addr_t baddr, bmask; int seg; /* * Make sure we don't cross any boundaries. */ bmask = ~(dmat->boundary - 1); if (dmat->boundary > 0) { baddr = (curaddr + dmat->boundary) & bmask; if (sgsize > (baddr - curaddr)) sgsize = (baddr - curaddr); } /* * Insert chunk into a segment, coalescing with * the previous segment if possible. */ seg = *segp; if (seg >= 0 && curaddr == segs[seg].ds_addr + segs[seg].ds_len && (segs[seg].ds_len + sgsize) <= dmat->maxsegsz && (dmat->boundary == 0 || (segs[seg].ds_addr & bmask) == (curaddr & bmask))) { segs[seg].ds_len += sgsize; } else { if (++seg >= dmat->nsegments) return (0); segs[seg].ds_addr = curaddr; segs[seg].ds_len = sgsize; } *segp = seg; return (sgsize); } /* * Utility function to load a physical buffer. segp contains * the starting segment on entrace, and the ending segment on exit. */ int _bus_dmamap_load_phys(bus_dma_tag_t dmat, bus_dmamap_t map, vm_paddr_t buf, bus_size_t buflen, int flags, bus_dma_segment_t *segs, int *segp) { bus_addr_t curaddr; bus_size_t sgsize; int error; if (segs == NULL) segs = dmat->segments; if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) { _bus_dmamap_count_phys(dmat, map, buf, buflen, flags); if (map->pagesneeded != 0) { error = _bus_dmamap_reserve_pages(dmat, map, flags); if (error) return (error); } } while (buflen > 0) { curaddr = buf; sgsize = MIN(buflen, dmat->maxsegsz); if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) && map->pagesneeded != 0 && run_filter(dmat, curaddr)) { sgsize = MIN(sgsize, PAGE_SIZE); curaddr = add_bounce_page(dmat, map, 0, curaddr, sgsize); } sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, segp); if (sgsize == 0) break; buf += sgsize; buflen -= sgsize; } /* * Did we fit? */ if (buflen != 0) { _bus_dmamap_unload(dmat, map); return (EFBIG); /* XXX better return value here? */ } return (0); } int _bus_dmamap_load_ma(bus_dma_tag_t dmat, bus_dmamap_t map, struct vm_page **ma, bus_size_t tlen, int ma_offs, int flags, bus_dma_segment_t *segs, int *segp) { return (bus_dmamap_load_ma_triv(dmat, map, ma, tlen, ma_offs, flags, segs, segp)); } /* * Utility function to load a linear buffer. segp contains * the starting segment on entrance, and the ending segment on exit. * first indicates if this is the first invocation of this function. */ int _bus_dmamap_load_buffer(bus_dma_tag_t dmat, bus_dmamap_t map, void *buf, bus_size_t buflen, struct pmap *pmap, int flags, bus_dma_segment_t *segs, int *segp) { bus_size_t sgsize; bus_addr_t curaddr; struct sync_list *sl; vm_offset_t vaddr = (vm_offset_t)buf; int error = 0; if (segs == NULL) segs = dmat->segments; if ((flags & BUS_DMA_LOAD_MBUF) != 0) map->flags |= DMAMAP_CACHE_ALIGNED; if ((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) { _bus_dmamap_count_pages(dmat, map, pmap, buf, buflen, flags); if (map->pagesneeded != 0) { error = _bus_dmamap_reserve_pages(dmat, map, flags); if (error) return (error); } } CTR3(KTR_BUSDMA, "lowaddr= %d boundary= %d, " "alignment= %d", dmat->lowaddr, dmat->boundary, dmat->alignment); while (buflen > 0) { /* * Get the physical address for this segment. * * XXX Don't support checking for coherent mappings * XXX in user address space. */ KASSERT(kernel_pmap == pmap, ("pmap is not kernel pmap")); curaddr = pmap_kextract(vaddr); /* * Compute the segment size, and adjust counts. */ sgsize = PAGE_SIZE - ((u_long)curaddr & PAGE_MASK); if (sgsize > dmat->maxsegsz) sgsize = dmat->maxsegsz; if (buflen < sgsize) sgsize = buflen; if (((dmat->flags & BUS_DMA_COULD_BOUNCE) != 0) && map->pagesneeded != 0 && run_filter(dmat, curaddr)) { curaddr = add_bounce_page(dmat, map, vaddr, curaddr, sgsize); } else { sl = &map->slist[map->sync_count - 1]; if (map->sync_count == 0 || vaddr != sl->vaddr + sl->datacount) { if (++map->sync_count > dmat->nsegments) goto cleanup; sl++; sl->vaddr = vaddr; sl->datacount = sgsize; sl->busaddr = curaddr; } else sl->datacount += sgsize; } sgsize = _bus_dmamap_addseg(dmat, map, curaddr, sgsize, segs, segp); if (sgsize == 0) break; vaddr += sgsize; buflen -= sgsize; } cleanup: /* * Did we fit? */ if (buflen != 0) { _bus_dmamap_unload(dmat, map); error = EFBIG; /* XXX better return value here? */ } return (error); } void __bus_dmamap_waitok(bus_dma_tag_t dmat, bus_dmamap_t map, struct memdesc *mem, bus_dmamap_callback_t *callback, void *callback_arg) { KASSERT(dmat != NULL, ("dmatag is NULL")); KASSERT(map != NULL, ("dmamap is NULL")); map->mem = *mem; map->callback = callback; map->callback_arg = callback_arg; } bus_dma_segment_t * _bus_dmamap_complete(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dma_segment_t *segs, int nsegs, int error) { if (segs == NULL) segs = dmat->segments; return (segs); } /* * Release the mapping held by map. */ void _bus_dmamap_unload(bus_dma_tag_t dmat, bus_dmamap_t map) { struct bounce_page *bpage; while ((bpage = STAILQ_FIRST(&map->bpages)) != NULL) { STAILQ_REMOVE_HEAD(&map->bpages, links); free_bounce_page(dmat, bpage); } map->sync_count = 0; return; } static void bus_dmamap_sync_buf(vm_offset_t buf, int len, bus_dmasync_op_t op, int aligned) { - char tmp_cl[mips_pdcache_linesize], tmp_clend[mips_pdcache_linesize]; + char tmp_cl[mips_dcache_max_linesize], tmp_clend[mips_dcache_max_linesize]; vm_offset_t buf_cl, buf_clend; vm_size_t size_cl, size_clend; - int cache_linesize_mask = mips_pdcache_linesize - 1; + int cache_linesize_mask = mips_dcache_max_linesize - 1; /* * dcache invalidation operates on cache line aligned addresses * and could modify areas of memory that share the same cache line * at the beginning and the ending of the buffer. In order to * prevent a data loss we save these chunks in temporary buffer * before invalidation and restore them afer it. * * If the aligned flag is set the buffer is either an mbuf or came from * our allocator caches. In both cases they are always sized and * aligned to cacheline boundaries, so we can skip preserving nearby * data if a transfer appears to overlap cachelines. An mbuf in * particular will usually appear to be overlapped because of offsetting * within the buffer to align the L3 headers, but we know that the bytes * preceeding that offset are part of the same mbuf memory and are not * unrelated adjacent data (and a rule of mbuf handling is that the cpu * is not allowed to touch the mbuf while dma is in progress, including * header fields). */ if (aligned) { size_cl = 0; size_clend = 0; } else { buf_cl = buf & ~cache_linesize_mask; size_cl = buf & cache_linesize_mask; buf_clend = buf + len; - size_clend = (mips_pdcache_linesize - + size_clend = (mips_dcache_max_linesize - (buf_clend & cache_linesize_mask)) & cache_linesize_mask; } switch (op) { case BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE: case BUS_DMASYNC_POSTREAD: /* * Save buffers that might be modified by invalidation */ if (size_cl) memcpy (tmp_cl, (void*)buf_cl, size_cl); if (size_clend) memcpy (tmp_clend, (void*)buf_clend, size_clend); mips_dcache_inv_range(buf, len); /* * Restore them */ if (size_cl) memcpy ((void*)buf_cl, tmp_cl, size_cl); if (size_clend) memcpy ((void*)buf_clend, tmp_clend, size_clend); /* * Copies above have brought corresponding memory * cache lines back into dirty state. Write them back * out and invalidate affected cache lines again if * necessary. */ if (size_cl) mips_dcache_wbinv_range(buf_cl, size_cl); if (size_clend && (size_cl == 0 || - buf_clend - buf_cl > mips_pdcache_linesize)) + buf_clend - buf_cl > mips_dcache_max_linesize)) mips_dcache_wbinv_range(buf_clend, size_clend); break; case BUS_DMASYNC_PREREAD|BUS_DMASYNC_PREWRITE: mips_dcache_wbinv_range(buf, len); break; case BUS_DMASYNC_PREREAD: /* * Save buffers that might be modified by invalidation */ if (size_cl) memcpy (tmp_cl, (void *)buf_cl, size_cl); if (size_clend) memcpy (tmp_clend, (void *)buf_clend, size_clend); mips_dcache_inv_range(buf, len); /* * Restore them */ if (size_cl) memcpy ((void *)buf_cl, tmp_cl, size_cl); if (size_clend) memcpy ((void *)buf_clend, tmp_clend, size_clend); /* * Copies above have brought corresponding memory * cache lines back into dirty state. Write them back * out and invalidate affected cache lines again if * necessary. */ if (size_cl) mips_dcache_wbinv_range(buf_cl, size_cl); if (size_clend && (size_cl == 0 || - buf_clend - buf_cl > mips_pdcache_linesize)) + buf_clend - buf_cl > mips_dcache_max_linesize)) mips_dcache_wbinv_range(buf_clend, size_clend); break; case BUS_DMASYNC_PREWRITE: mips_dcache_wb_range(buf, len); break; } } static void _bus_dmamap_sync_bp(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) { struct bounce_page *bpage; STAILQ_FOREACH(bpage, &map->bpages, links) { if (op & BUS_DMASYNC_PREWRITE) { if (bpage->datavaddr != 0) bcopy((void *)bpage->datavaddr, (void *)(bpage->vaddr_nocache != 0 ? bpage->vaddr_nocache : bpage->vaddr), bpage->datacount); else physcopyout(bpage->dataaddr, (void *)(bpage->vaddr_nocache != 0 ? bpage->vaddr_nocache : bpage->vaddr), bpage->datacount); if (bpage->vaddr_nocache == 0) { mips_dcache_wb_range(bpage->vaddr, bpage->datacount); } dmat->bounce_zone->total_bounced++; } if (op & BUS_DMASYNC_POSTREAD) { if (bpage->vaddr_nocache == 0) { mips_dcache_inv_range(bpage->vaddr, bpage->datacount); } if (bpage->datavaddr != 0) bcopy((void *)(bpage->vaddr_nocache != 0 ? bpage->vaddr_nocache : bpage->vaddr), (void *)bpage->datavaddr, bpage->datacount); else physcopyin((void *)(bpage->vaddr_nocache != 0 ? bpage->vaddr_nocache : bpage->vaddr), bpage->dataaddr, bpage->datacount); dmat->bounce_zone->total_bounced++; } } } void _bus_dmamap_sync(bus_dma_tag_t dmat, bus_dmamap_t map, bus_dmasync_op_t op) { struct sync_list *sl, *end; int aligned; if (op == BUS_DMASYNC_POSTWRITE) return; if (STAILQ_FIRST(&map->bpages)) _bus_dmamap_sync_bp(dmat, map, op); if ((dmat->flags & BUS_DMA_COHERENT) || (map->flags & DMAMAP_UNCACHEABLE)) { if (op & BUS_DMASYNC_PREWRITE) mips_sync(); return; } aligned = (map->flags & DMAMAP_CACHE_ALIGNED) ? 1 : 0; CTR3(KTR_BUSDMA, "%s: op %x flags %x", __func__, op, map->flags); if (map->sync_count) { end = &map->slist[map->sync_count]; for (sl = &map->slist[0]; sl != end; sl++) bus_dmamap_sync_buf(sl->vaddr, sl->datacount, op, aligned); } } static void init_bounce_pages(void *dummy __unused) { total_bpages = 0; STAILQ_INIT(&bounce_zone_list); STAILQ_INIT(&bounce_map_waitinglist); STAILQ_INIT(&bounce_map_callbacklist); mtx_init(&bounce_lock, "bounce pages lock", NULL, MTX_DEF); } SYSINIT(bpages, SI_SUB_LOCK, SI_ORDER_ANY, init_bounce_pages, NULL); static struct sysctl_ctx_list * busdma_sysctl_tree(struct bounce_zone *bz) { return (&bz->sysctl_tree); } static struct sysctl_oid * busdma_sysctl_tree_top(struct bounce_zone *bz) { return (bz->sysctl_tree_top); } static int alloc_bounce_zone(bus_dma_tag_t dmat) { struct bounce_zone *bz; /* Check to see if we already have a suitable zone */ STAILQ_FOREACH(bz, &bounce_zone_list, links) { if ((dmat->alignment <= bz->alignment) && (dmat->lowaddr >= bz->lowaddr)) { dmat->bounce_zone = bz; return (0); } } if ((bz = (struct bounce_zone *)malloc(sizeof(*bz), M_BUSDMA, M_NOWAIT | M_ZERO)) == NULL) return (ENOMEM); STAILQ_INIT(&bz->bounce_page_list); bz->free_bpages = 0; bz->reserved_bpages = 0; bz->active_bpages = 0; bz->lowaddr = dmat->lowaddr; bz->alignment = MAX(dmat->alignment, PAGE_SIZE); bz->map_count = 0; snprintf(bz->zoneid, 8, "zone%d", busdma_zonecount); busdma_zonecount++; snprintf(bz->lowaddrid, 18, "%#jx", (uintmax_t)bz->lowaddr); STAILQ_INSERT_TAIL(&bounce_zone_list, bz, links); dmat->bounce_zone = bz; sysctl_ctx_init(&bz->sysctl_tree); bz->sysctl_tree_top = SYSCTL_ADD_NODE(&bz->sysctl_tree, SYSCTL_STATIC_CHILDREN(_hw_busdma), OID_AUTO, bz->zoneid, CTLFLAG_RD, 0, ""); if (bz->sysctl_tree_top == NULL) { sysctl_ctx_free(&bz->sysctl_tree); return (0); /* XXX error code? */ } SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "total_bpages", CTLFLAG_RD, &bz->total_bpages, 0, "Total bounce pages"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "free_bpages", CTLFLAG_RD, &bz->free_bpages, 0, "Free bounce pages"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "reserved_bpages", CTLFLAG_RD, &bz->reserved_bpages, 0, "Reserved bounce pages"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "active_bpages", CTLFLAG_RD, &bz->active_bpages, 0, "Active bounce pages"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "total_bounced", CTLFLAG_RD, &bz->total_bounced, 0, "Total bounce requests"); SYSCTL_ADD_INT(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "total_deferred", CTLFLAG_RD, &bz->total_deferred, 0, "Total bounce requests that were deferred"); SYSCTL_ADD_STRING(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "lowaddr", CTLFLAG_RD, bz->lowaddrid, 0, ""); SYSCTL_ADD_UAUTO(busdma_sysctl_tree(bz), SYSCTL_CHILDREN(busdma_sysctl_tree_top(bz)), OID_AUTO, "alignment", CTLFLAG_RD, &bz->alignment, ""); return (0); } static int alloc_bounce_pages(bus_dma_tag_t dmat, u_int numpages) { struct bounce_zone *bz; int count; bz = dmat->bounce_zone; count = 0; while (numpages > 0) { struct bounce_page *bpage; bpage = (struct bounce_page *)malloc(sizeof(*bpage), M_BUSDMA, M_NOWAIT | M_ZERO); if (bpage == NULL) break; bpage->vaddr = (vm_offset_t)contigmalloc(PAGE_SIZE, M_BOUNCE, M_NOWAIT, 0ul, bz->lowaddr, PAGE_SIZE, 0); if (bpage->vaddr == 0) { free(bpage, M_BUSDMA); break; } bpage->busaddr = pmap_kextract(bpage->vaddr); bpage->vaddr_nocache = (vm_offset_t)pmap_mapdev(bpage->busaddr, PAGE_SIZE); mtx_lock(&bounce_lock); STAILQ_INSERT_TAIL(&bz->bounce_page_list, bpage, links); total_bpages++; bz->total_bpages++; bz->free_bpages++; mtx_unlock(&bounce_lock); count++; numpages--; } return (count); } static int reserve_bounce_pages(bus_dma_tag_t dmat, bus_dmamap_t map, int commit) { struct bounce_zone *bz; int pages; mtx_assert(&bounce_lock, MA_OWNED); bz = dmat->bounce_zone; pages = MIN(bz->free_bpages, map->pagesneeded - map->pagesreserved); if (commit == 0 && map->pagesneeded > (map->pagesreserved + pages)) return (map->pagesneeded - (map->pagesreserved + pages)); bz->free_bpages -= pages; bz->reserved_bpages += pages; map->pagesreserved += pages; pages = map->pagesneeded - map->pagesreserved; return (pages); } static bus_addr_t add_bounce_page(bus_dma_tag_t dmat, bus_dmamap_t map, vm_offset_t vaddr, bus_addr_t addr, bus_size_t size) { struct bounce_zone *bz; struct bounce_page *bpage; KASSERT(dmat->bounce_zone != NULL, ("no bounce zone in dma tag")); KASSERT(map != NULL, ("add_bounce_page: bad map %p", map)); bz = dmat->bounce_zone; if (map->pagesneeded == 0) panic("add_bounce_page: map doesn't need any pages"); map->pagesneeded--; if (map->pagesreserved == 0) panic("add_bounce_page: map doesn't need any pages"); map->pagesreserved--; mtx_lock(&bounce_lock); bpage = STAILQ_FIRST(&bz->bounce_page_list); if (bpage == NULL) panic("add_bounce_page: free page list is empty"); STAILQ_REMOVE_HEAD(&bz->bounce_page_list, links); bz->reserved_bpages--; bz->active_bpages++; mtx_unlock(&bounce_lock); if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) { /* Page offset needs to be preserved. */ bpage->vaddr |= addr & PAGE_MASK; bpage->busaddr |= addr & PAGE_MASK; } bpage->datavaddr = vaddr; bpage->dataaddr = addr; bpage->datacount = size; STAILQ_INSERT_TAIL(&(map->bpages), bpage, links); return (bpage->busaddr); } static void free_bounce_page(bus_dma_tag_t dmat, struct bounce_page *bpage) { struct bus_dmamap *map; struct bounce_zone *bz; bz = dmat->bounce_zone; bpage->datavaddr = 0; bpage->datacount = 0; if (dmat->flags & BUS_DMA_KEEP_PG_OFFSET) { /* * Reset the bounce page to start at offset 0. Other uses * of this bounce page may need to store a full page of * data and/or assume it starts on a page boundary. */ bpage->vaddr &= ~PAGE_MASK; bpage->busaddr &= ~PAGE_MASK; } mtx_lock(&bounce_lock); STAILQ_INSERT_HEAD(&bz->bounce_page_list, bpage, links); bz->free_bpages++; bz->active_bpages--; if ((map = STAILQ_FIRST(&bounce_map_waitinglist)) != NULL) { if (reserve_bounce_pages(map->dmat, map, 1) == 0) { STAILQ_REMOVE_HEAD(&bounce_map_waitinglist, links); STAILQ_INSERT_TAIL(&bounce_map_callbacklist, map, links); busdma_swi_pending = 1; bz->total_deferred++; swi_sched(vm_ih, 0); } } mtx_unlock(&bounce_lock); } void busdma_swi(void) { bus_dma_tag_t dmat; struct bus_dmamap *map; mtx_lock(&bounce_lock); while ((map = STAILQ_FIRST(&bounce_map_callbacklist)) != NULL) { STAILQ_REMOVE_HEAD(&bounce_map_callbacklist, links); mtx_unlock(&bounce_lock); dmat = map->dmat; (dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_LOCK); bus_dmamap_load_mem(map->dmat, map, &map->mem, map->callback, map->callback_arg, BUS_DMA_WAITOK); (dmat->lockfunc)(dmat->lockfuncarg, BUS_DMA_UNLOCK); mtx_lock(&bounce_lock); } mtx_unlock(&bounce_lock); } Index: projects/clang390-import/sys/mips/mips/cache_mipsNN.c =================================================================== --- projects/clang390-import/sys/mips/mips/cache_mipsNN.c (revision 308867) +++ projects/clang390-import/sys/mips/mips/cache_mipsNN.c (revision 308868) @@ -1,1375 +1,1382 @@ /* $NetBSD: cache_mipsNN.c,v 1.10 2005/12/24 20:07:19 perry Exp $ */ /* * Copyright 2001 Wasabi Systems, Inc. * All rights reserved. * * Written by Jason R. Thorpe and Simon Burge for Wasabi Systems, Inc. * * 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. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed for the NetBSD Project by * Wasabi Systems, Inc. * 4. The name of Wasabi Systems, Inc. may not be used to endorse * or promote products derived from this software without specific prior * written permission. * * THIS SOFTWARE IS PROVIDED BY WASABI SYSTEMS, INC. ``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 WASABI SYSTEMS, INC * 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 __FBSDID("$FreeBSD$"); #include #include #include #include #include #include #define round_line16(x) (((x) + 15) & ~15) #define trunc_line16(x) ((x) & ~15) #define round_line32(x) (((x) + 31) & ~31) #define trunc_line32(x) ((x) & ~31) #define round_line64(x) (((x) + 63) & ~63) #define trunc_line64(x) ((x) & ~63) #define round_line128(x) (((x) + 127) & ~127) #define trunc_line128(x) ((x) & ~127) #if defined(CPU_NLM) static __inline void xlp_sync(void) { __asm __volatile ( ".set push \n" ".set noreorder \n" ".set mips64 \n" "dla $8, 1f \n" "/* jr.hb $8 */ \n" ".word 0x1000408 \n" "nop \n" "1: nop \n" ".set pop \n" : : : "$8"); } #endif #if defined(SB1250_PASS1) #define SYNC __asm volatile("sync; sync") #elif defined(CPU_NLM) #define SYNC xlp_sync() #else #define SYNC __asm volatile("sync") #endif #if defined(CPU_CNMIPS) #define SYNCI mips_sync_icache(); #elif defined(CPU_NLM) #define SYNCI xlp_sync() #else #define SYNCI #endif /* * Exported variables for consumers like bus_dma code */ int mips_picache_linesize; int mips_pdcache_linesize; +int mips_sdcache_linesize; +int mips_dcache_max_linesize; static int picache_size; static int picache_stride; static int picache_loopcount; static int picache_way_mask; static int pdcache_size; static int pdcache_stride; static int pdcache_loopcount; static int pdcache_way_mask; static int sdcache_size; static int sdcache_stride; static int sdcache_loopcount; static int sdcache_way_mask; void mipsNN_cache_init(struct mips_cpuinfo * cpuinfo) { int flush_multiple_lines_per_way; flush_multiple_lines_per_way = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize * cpuinfo->l1.ic_linesize > PAGE_SIZE; if (cpuinfo->icache_virtual) { /* * With a virtual Icache we don't need to flush * multiples of the page size with index ops; we just * need to flush one pages' worth. */ flush_multiple_lines_per_way = 0; } if (flush_multiple_lines_per_way) { picache_stride = PAGE_SIZE; picache_loopcount = (cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize / PAGE_SIZE) * cpuinfo->l1.ic_nways; } else { picache_stride = cpuinfo->l1.ic_nsets * cpuinfo->l1.ic_linesize; picache_loopcount = cpuinfo->l1.ic_nways; } if (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize < PAGE_SIZE) { pdcache_stride = cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize; pdcache_loopcount = cpuinfo->l1.dc_nways; } else { pdcache_stride = PAGE_SIZE; pdcache_loopcount = (cpuinfo->l1.dc_nsets * cpuinfo->l1.dc_linesize / PAGE_SIZE) * cpuinfo->l1.dc_nways; } mips_picache_linesize = cpuinfo->l1.ic_linesize; mips_pdcache_linesize = cpuinfo->l1.dc_linesize; picache_size = cpuinfo->l1.ic_size; picache_way_mask = cpuinfo->l1.ic_nways - 1; pdcache_size = cpuinfo->l1.dc_size; pdcache_way_mask = cpuinfo->l1.dc_nways - 1; sdcache_stride = cpuinfo->l2.dc_nsets * cpuinfo->l2.dc_linesize; sdcache_loopcount = cpuinfo->l2.dc_nways; sdcache_size = cpuinfo->l2.dc_size; sdcache_way_mask = cpuinfo->l2.dc_nways - 1; + mips_sdcache_linesize = cpuinfo->l2.dc_linesize; + mips_dcache_max_linesize = MAX(mips_pdcache_linesize, + mips_sdcache_linesize); + #define CACHE_DEBUG #ifdef CACHE_DEBUG printf("Cache info:\n"); if (cpuinfo->icache_virtual) printf(" icache is virtual\n"); printf(" picache_stride = %d\n", picache_stride); printf(" picache_loopcount = %d\n", picache_loopcount); printf(" pdcache_stride = %d\n", pdcache_stride); printf(" pdcache_loopcount = %d\n", pdcache_loopcount); + printf(" max line size = %d\n", mips_dcache_max_linesize); #endif } void mipsNN_icache_sync_all_16(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + picache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ mips_intern_dcache_wbinv_all(); while (va < eva) { cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += (32 * 16); } SYNC; } void mipsNN_icache_sync_all_32(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + picache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ mips_intern_dcache_wbinv_all(); while (va < eva) { cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += (32 * 32); } SYNC; } void mipsNN_icache_sync_all_64(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + picache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ mips_intern_dcache_wbinv_all(); while (va < eva) { cache_r4k_op_32lines_64(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += (32 * 64); } SYNC; } void mipsNN_icache_sync_range_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line16(va + size); va = trunc_line16(va); mips_intern_dcache_wb_range(va, (eva - va)); while ((eva - va) >= (32 * 16)) { cache_r4k_op_32lines_16(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += (32 * 16); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += 16; } SYNC; } void mipsNN_icache_sync_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line32(va + size); va = trunc_line32(va); mips_intern_dcache_wb_range(va, (eva - va)); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += 32; } SYNC; } void mipsNN_icache_sync_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line64(va + size); va = trunc_line64(va); mips_intern_dcache_wb_range(va, (eva - va)); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += 64; } SYNC; } void mipsNN_icache_sync_range_index_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); eva = round_line16(va + size); va = trunc_line16(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = picache_stride; loopcount = picache_loopcount; mips_intern_dcache_wbinv_range_index(va, (eva - va)); while ((eva - va) >= (8 * 16)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_16(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 8 * 16; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 16; } } void mipsNN_icache_sync_range_index_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); eva = round_line32(va + size); va = trunc_line32(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = picache_stride; loopcount = picache_loopcount; mips_intern_dcache_wbinv_range_index(va, (eva - va)); while ((eva - va) >= (8 * 32)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_32(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 8 * 32; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 32; } } void mipsNN_icache_sync_range_index_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); eva = round_line64(va + size); va = trunc_line64(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = picache_stride; loopcount = picache_loopcount; mips_intern_dcache_wbinv_range_index(va, (eva - va)); while ((eva - va) >= (8 * 64)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_64(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 8 * 64; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 64; } } void mipsNN_pdcache_wbinv_all_16(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + pdcache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ while (va < eva) { cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 16); } SYNC; } void mipsNN_pdcache_wbinv_all_32(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + pdcache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ while (va < eva) { cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 32); } SYNC; } void mipsNN_pdcache_wbinv_all_64(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + pdcache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ while (va < eva) { cache_r4k_op_32lines_64(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 64); } SYNC; } void mipsNN_pdcache_wbinv_range_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line16(va + size); va = trunc_line16(va); while ((eva - va) >= (32 * 16)) { cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += (32 * 16); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += 16; } SYNC; } void mipsNN_pdcache_wbinv_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += 32; } SYNC; } void mipsNN_pdcache_wbinv_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += 64; } SYNC; } void mipsNN_pdcache_wbinv_range_index_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); eva = round_line16(va + size); va = trunc_line16(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = pdcache_stride; loopcount = pdcache_loopcount; while ((eva - va) >= (8 * 16)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_16(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 8 * 16; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 16; } } void mipsNN_pdcache_wbinv_range_index_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); eva = round_line32(va + size); va = trunc_line32(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = pdcache_stride; loopcount = pdcache_loopcount; while ((eva - va) >= (8 * 32)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_32(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 8 * 32; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 32; } } void mipsNN_pdcache_wbinv_range_index_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); eva = round_line64(va + size); va = trunc_line64(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = pdcache_stride; loopcount = pdcache_loopcount; while ((eva - va) >= (8 * 64)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_8lines_64(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 8 * 64; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 64; } } void mipsNN_pdcache_inv_range_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line16(va + size); va = trunc_line16(va); while ((eva - va) >= (32 * 16)) { cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += (32 * 16); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += 16; } SYNC; } void mipsNN_pdcache_inv_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += 32; } SYNC; } void mipsNN_pdcache_inv_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += 64; } SYNC; } void mipsNN_pdcache_wb_range_16(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line16(va + size); va = trunc_line16(va); while ((eva - va) >= (32 * 16)) { cache_r4k_op_32lines_16(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += (32 * 16); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += 16; } SYNC; } void mipsNN_pdcache_wb_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += 32; } SYNC; } void mipsNN_pdcache_wb_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += 64; } SYNC; } #ifdef CPU_CNMIPS void mipsNN_icache_sync_all_128(void) { SYNCI } void mipsNN_icache_sync_range_128(vm_offset_t va, vm_size_t size) { SYNC; } void mipsNN_icache_sync_range_index_128(vm_offset_t va, vm_size_t size) { } void mipsNN_pdcache_wbinv_all_128(void) { } void mipsNN_pdcache_wbinv_range_128(vm_offset_t va, vm_size_t size) { SYNC; } void mipsNN_pdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size) { } void mipsNN_pdcache_inv_range_128(vm_offset_t va, vm_size_t size) { } void mipsNN_pdcache_wb_range_128(vm_offset_t va, vm_size_t size) { SYNC; } #else void mipsNN_icache_sync_all_128(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + picache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ mips_intern_dcache_wbinv_all(); while (va < eva) { cache_r4k_op_32lines_128(va, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += (32 * 128); } SYNC; } void mipsNN_icache_sync_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line128(va + size); va = trunc_line128(va); mips_intern_dcache_wb_range(va, (eva - va)); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_I|CACHEOP_R4K_HIT_INV); va += 128; } SYNC; } void mipsNN_icache_sync_range_index_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & picache_way_mask); eva = round_line128(va + size); va = trunc_line128(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = picache_stride; loopcount = picache_loopcount; mips_intern_dcache_wbinv_range_index(va, (eva - va)); while ((eva - va) >= (32 * 128)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_32lines_128(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 32 * 128; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_I|CACHEOP_R4K_INDEX_INV); va += 128; } } void mipsNN_pdcache_wbinv_all_128(void) { vm_offset_t va, eva; va = MIPS_PHYS_TO_KSEG0(0); eva = va + pdcache_size; /* * Since we're hitting the whole thing, we don't have to * worry about the N different "ways". */ while (va < eva) { cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 128); } SYNC; } void mipsNN_pdcache_wbinv_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB_INV); va += 128; } SYNC; } void mipsNN_pdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva, tmpva; int i, stride, loopcount; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & pdcache_way_mask); eva = round_line128(va + size); va = trunc_line128(va); /* * GCC generates better code in the loops if we reference local * copies of these global variables. */ stride = pdcache_stride; loopcount = pdcache_loopcount; while ((eva - va) >= (32 * 128)) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_r4k_op_32lines_128(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 32 * 128; } while (va < eva) { tmpva = va; for (i = 0; i < loopcount; i++, tmpva += stride) cache_op_r4k_line(tmpva, CACHE_R4K_D|CACHEOP_R4K_INDEX_WB_INV); va += 128; } } void mipsNN_pdcache_inv_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_INV); va += 128; } SYNC; } void mipsNN_pdcache_wb_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_D|CACHEOP_R4K_HIT_WB); va += 128; } SYNC; } #endif void mipsNN_sdcache_wbinv_all_32(void) { vm_offset_t va = MIPS_PHYS_TO_KSEG0(0); vm_offset_t eva = va + sdcache_size; while (va < eva) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 32); } } void mipsNN_sdcache_wbinv_all_64(void) { vm_offset_t va = MIPS_PHYS_TO_KSEG0(0); vm_offset_t eva = va + sdcache_size; while (va < eva) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 64); } } void mipsNN_sdcache_wbinv_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += 32; } } void mipsNN_sdcache_wbinv_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += 64; } } void mipsNN_sdcache_wbinv_range_index_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & (sdcache_size - 1)); eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += 32; } } void mipsNN_sdcache_wbinv_range_index_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & (sdcache_size - 1)); eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += 64; } } void mipsNN_sdcache_inv_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += 32; } } void mipsNN_sdcache_inv_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += 64; } } void mipsNN_sdcache_wb_range_32(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line32(va + size); va = trunc_line32(va); while ((eva - va) >= (32 * 32)) { cache_r4k_op_32lines_32(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += (32 * 32); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += 32; } } void mipsNN_sdcache_wb_range_64(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line64(va + size); va = trunc_line64(va); while ((eva - va) >= (32 * 64)) { cache_r4k_op_32lines_64(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += (32 * 64); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += 64; } } void mipsNN_sdcache_wbinv_all_128(void) { vm_offset_t va = MIPS_PHYS_TO_KSEG0(0); vm_offset_t eva = va + sdcache_size; while (va < eva) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 128); } } void mipsNN_sdcache_wbinv_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB_INV); va += 128; } } void mipsNN_sdcache_wbinv_range_index_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva; /* * Since we're doing Index ops, we expect to not be able * to access the address we've been given. So, get the * bits that determine the cache index, and make a KSEG0 * address out of them. */ va = MIPS_PHYS_TO_KSEG0(va & (sdcache_size - 1)); eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_INDEX_WB_INV); va += 128; } } void mipsNN_sdcache_inv_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_INV); va += 128; } } void mipsNN_sdcache_wb_range_128(vm_offset_t va, vm_size_t size) { vm_offset_t eva = round_line128(va + size); va = trunc_line128(va); while ((eva - va) >= (32 * 128)) { cache_r4k_op_32lines_128(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += (32 * 128); } while (va < eva) { cache_op_r4k_line(va, CACHE_R4K_SD|CACHEOP_R4K_HIT_WB); va += 128; } } Index: projects/clang390-import/sys/mips/mips/exception.S =================================================================== --- projects/clang390-import/sys/mips/mips/exception.S (revision 308867) +++ projects/clang390-import/sys/mips/mips/exception.S (revision 308868) @@ -1,1271 +1,1275 @@ /* $OpenBSD: locore.S,v 1.18 1998/09/15 10:58:53 pefo Exp $ */ /*- * Copyright (c) 1992, 1993 * The Regents of the University of California. All rights reserved. * * This code is derived from software contributed to Berkeley by * Digital Equipment Corporation and Ralph Campbell. * * 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. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS 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 REGENTS 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. * * Copyright (C) 1989 Digital Equipment Corporation. * Permission to use, copy, modify, and distribute this software and * its documentation for any purpose and without fee is hereby granted, * provided that the above copyright notice appears in all copies. * Digital Equipment Corporation makes no representations about the * suitability of this software for any purpose. It is provided "as is" * without express or implied warranty. * * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/loMem.s, * v 1.1 89/07/11 17:55:04 nelson Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/mach/ds3100.md/RCS/machAsm.s, * v 9.2 90/01/29 18:00:39 shirriff Exp SPRITE (DECWRL) * from: Header: /sprite/src/kernel/vm/ds3100.md/vmPmaxAsm.s, * v 1.1 89/07/10 14:27:41 nelson Exp SPRITE (DECWRL) * from: @(#)locore.s 8.5 (Berkeley) 1/4/94 * JNPR: exception.S,v 1.5 2007/01/08 04:58:37 katta * $FreeBSD$ */ /* * Contains code that is the first executed at boot time plus * assembly language support routines. */ #include "opt_ddb.h" #include #include #include #include #include #include #include "assym.s" .set noreorder # Noreorder is default style! #ifdef KDTRACE_HOOKS .data .globl dtrace_invop_calltrap_addr .align 4 .type dtrace_invop_calltrap_addr, @object .size dtrace_invop_calltrap_addr, 8 dtrace_invop_calltrap_addr: .word 0 .word 0 .text #endif /* * Reasonable limit */ #define INTRCNT_COUNT 256 /* *---------------------------------------------------------------------------- * * MipsTLBMiss -- * * Vector code for the TLB-miss exception vector 0x80000000. * * This code is copied to the TLB exception vector address to * which the CPU jumps in response to an exception or a TLB miss. * NOTE: This code must be position independent!!! * * */ VECTOR(MipsTLBMiss, unknown) .set push .set noat j MipsDoTLBMiss MFC0 k0, MIPS_COP_0_BAD_VADDR # get the fault address .set pop VECTOR_END(MipsTLBMiss) /* *---------------------------------------------------------------------------- * * MipsDoTLBMiss -- * * This is the real TLB Miss Handler code. * 'segbase' points to the base of the segment table for user processes. * * Don't check for invalid pte's here. We load them as well and * let the processor trap to load the correct value after service. *---------------------------------------------------------------------------- */ .set push .set noat MipsDoTLBMiss: bltz k0, 1f #02: k0<0 -> 1f (kernel fault) PTR_SRL k0, k0, SEGSHIFT - PTRSHIFT #03: k0=seg offset (almost) GET_CPU_PCPU(k1) PTR_L k1, PC_SEGBASE(k1) beqz k1, 2f #05: make sure segbase is not null andi k0, k0, PDEPTRMASK #06: k0=seg offset PTR_ADDU k1, k0, k1 #07: k1=seg entry address PTR_L k1, 0(k1) #08: k1=seg entry MFC0 k0, MIPS_COP_0_BAD_VADDR #09: k0=bad address (again) beq k1, zero, 2f #0a: ==0 -- no page table #ifdef __mips_n64 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN andi k0, k0, PDEPTRMASK # k0=pde offset PTR_ADDU k1, k0, k1 # k1=pde entry address PTR_L k1, 0(k1) # k1=pde entry MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) beq k1, zero, 2f # ==0 -- no page table #endif PTR_SRL k0, PAGE_SHIFT - PTESHIFT #0b: k0=VPN (aka va>>10) andi k0, k0, PTE2MASK #0c: k0=page tab offset PTR_ADDU k1, k1, k0 #0d: k1=pte address PTE_L k0, 0(k1) #0e: k0=lo0 pte PTE_L k1, PTESIZE(k1) #0f: k1=lo0 pte CLEAR_PTE_SWBITS(k0) PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 #12: lo0 is loaded COP0_SYNC CLEAR_PTE_SWBITS(k1) PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 #15: lo1 is loaded COP0_SYNC tlbwr #1a: write to tlb HAZARD_DELAY eret #1f: retUrn from exception 1: j MipsTLBMissException #20: kernel exception nop #21: branch delay slot 2: j SlowFault #22: no page table present nop #23: branch delay slot .set pop /* * This code is copied to the general exception vector address to * handle all execptions except RESET and TLBMiss. * NOTE: This code must be position independent!!! */ VECTOR(MipsException, unknown) /* * Find out what mode we came from and jump to the proper handler. * * Note: at turned off here because we cannot trash the at register * in this exception code. Only k0 and k1 may be modified before * we save registers. This is true of all functions called through * the pointer magic: Mips{User,Kern}Intr, Mips{User,Kern}GenException * and MipsTLBInvalidException */ .set noat mfc0 k0, MIPS_COP_0_STATUS # Get the status register mfc0 k1, MIPS_COP_0_CAUSE # Get the cause register value. and k0, k0, MIPS_SR_KSU_USER # test for user mode # sneaky but the bits are # with us........ sll k0, k0, 3 # shift user bit for cause index and k1, k1, MIPS_CR_EXC_CODE # Mask out the cause bits. or k1, k1, k0 # change index to user table #if defined(__mips_n64) PTR_SLL k1, k1, 1 # shift to get 8-byte offset #endif 1: PTR_LA k0, _C_LABEL(machExceptionTable) # get base of the jump table PTR_ADDU k0, k0, k1 # Get the address of the # function entry. Note that # the cause is already # shifted left by 2 bits so # we dont have to shift. PTR_L k0, 0(k0) # Get the function address nop j k0 # Jump to the function. nop .set at VECTOR_END(MipsException) /* * We couldn't find a TLB entry. * Find out what mode we came from and call the appropriate handler. */ SlowFault: .set noat mfc0 k0, MIPS_COP_0_STATUS nop and k0, k0, MIPS_SR_KSU_USER bne k0, zero, _C_LABEL(MipsUserGenException) nop .set at /* * Fall though ... */ /*---------------------------------------------------------------------------- * * MipsKernGenException -- * * Handle an exception from kernel mode. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ #define SAVE_REG(reg, offs, base) \ REG_S reg, CALLFRAME_SIZ + (SZREG * offs) (base) #if defined(CPU_CNMIPS) #define CLEAR_STATUS \ mfc0 a0, MIPS_COP_0_STATUS ;\ li a2, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX) ; \ or a0, a0, a2 ; \ li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ and a0, a0, a2 ; \ mtc0 a0, MIPS_COP_0_STATUS ; \ ITLBNOPFIX #elif defined(CPU_RMI) || defined(CPU_NLM) #define CLEAR_STATUS \ mfc0 a0, MIPS_COP_0_STATUS ;\ li a2, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) ; \ or a0, a0, a2 ; \ li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ and a0, a0, a2 ; \ mtc0 a0, MIPS_COP_0_STATUS ; \ ITLBNOPFIX #else #define CLEAR_STATUS \ mfc0 a0, MIPS_COP_0_STATUS ;\ li a2, ~(MIPS_SR_INT_IE | MIPS_SR_EXL | MIPS_SR_KSU_USER) ; \ and a0, a0, a2 ; \ mtc0 a0, MIPS_COP_0_STATUS ; \ ITLBNOPFIX #endif /* * Save CPU and CP0 register state. * * This is straightforward except for saving the exception program * counter. The ddb backtrace code looks for the first instruction * matching the form "sw ra, (off)sp" to figure out the address of the * calling function. So we must make sure that we save the exception * PC by staging it through 'ra' as opposed to any other register. */ #define SAVE_CPU \ SAVE_REG(AT, AST, sp) ;\ .set at ; \ SAVE_REG(v0, V0, sp) ;\ SAVE_REG(v1, V1, sp) ;\ SAVE_REG(a0, A0, sp) ;\ SAVE_REG(a1, A1, sp) ;\ SAVE_REG(a2, A2, sp) ;\ SAVE_REG(a3, A3, sp) ;\ SAVE_REG(t0, T0, sp) ;\ SAVE_REG(t1, T1, sp) ;\ SAVE_REG(t2, T2, sp) ;\ SAVE_REG(t3, T3, sp) ;\ SAVE_REG(ta0, TA0, sp) ;\ SAVE_REG(ta1, TA1, sp) ;\ SAVE_REG(ta2, TA2, sp) ;\ SAVE_REG(ta3, TA3, sp) ;\ SAVE_REG(t8, T8, sp) ;\ SAVE_REG(t9, T9, sp) ;\ SAVE_REG(gp, GP, sp) ;\ SAVE_REG(s0, S0, sp) ;\ SAVE_REG(s1, S1, sp) ;\ SAVE_REG(s2, S2, sp) ;\ SAVE_REG(s3, S3, sp) ;\ SAVE_REG(s4, S4, sp) ;\ SAVE_REG(s5, S5, sp) ;\ SAVE_REG(s6, S6, sp) ;\ SAVE_REG(s7, S7, sp) ;\ SAVE_REG(s8, S8, sp) ;\ mflo v0 ;\ mfhi v1 ;\ mfc0 a0, MIPS_COP_0_STATUS ;\ mfc0 a1, MIPS_COP_0_CAUSE ;\ MFC0 a2, MIPS_COP_0_BAD_VADDR;\ MFC0 a3, MIPS_COP_0_EXC_PC ;\ SAVE_REG(v0, MULLO, sp) ;\ SAVE_REG(v1, MULHI, sp) ;\ SAVE_REG(a0, SR, sp) ;\ SAVE_REG(a1, CAUSE, sp) ;\ SAVE_REG(a2, BADVADDR, sp) ;\ move t0, ra ;\ move ra, a3 ;\ SAVE_REG(ra, PC, sp) ;\ move ra, t0 ;\ SAVE_REG(ra, RA, sp) ;\ PTR_ADDU v0, sp, KERN_EXC_FRAME_SIZE ;\ SAVE_REG(v0, SP, sp) ;\ CLEAR_STATUS ;\ PTR_ADDU a0, sp, CALLFRAME_SIZ ;\ ITLBNOPFIX #define RESTORE_REG(reg, offs, base) \ REG_L reg, CALLFRAME_SIZ + (SZREG * offs) (base) #define RESTORE_CPU \ CLEAR_STATUS ;\ RESTORE_REG(k0, SR, sp) ;\ RESTORE_REG(t0, MULLO, sp) ;\ RESTORE_REG(t1, MULHI, sp) ;\ mtlo t0 ;\ mthi t1 ;\ MTC0 v0, MIPS_COP_0_EXC_PC ;\ .set noat ;\ RESTORE_REG(AT, AST, sp) ;\ RESTORE_REG(v0, V0, sp) ;\ RESTORE_REG(v1, V1, sp) ;\ RESTORE_REG(a0, A0, sp) ;\ RESTORE_REG(a1, A1, sp) ;\ RESTORE_REG(a2, A2, sp) ;\ RESTORE_REG(a3, A3, sp) ;\ RESTORE_REG(t0, T0, sp) ;\ RESTORE_REG(t1, T1, sp) ;\ RESTORE_REG(t2, T2, sp) ;\ RESTORE_REG(t3, T3, sp) ;\ RESTORE_REG(ta0, TA0, sp) ;\ RESTORE_REG(ta1, TA1, sp) ;\ RESTORE_REG(ta2, TA2, sp) ;\ RESTORE_REG(ta3, TA3, sp) ;\ RESTORE_REG(t8, T8, sp) ;\ RESTORE_REG(t9, T9, sp) ;\ RESTORE_REG(s0, S0, sp) ;\ RESTORE_REG(s1, S1, sp) ;\ RESTORE_REG(s2, S2, sp) ;\ RESTORE_REG(s3, S3, sp) ;\ RESTORE_REG(s4, S4, sp) ;\ RESTORE_REG(s5, S5, sp) ;\ RESTORE_REG(s6, S6, sp) ;\ RESTORE_REG(s7, S7, sp) ;\ RESTORE_REG(s8, S8, sp) ;\ RESTORE_REG(gp, GP, sp) ;\ RESTORE_REG(ra, RA, sp) ;\ PTR_ADDU sp, sp, KERN_EXC_FRAME_SIZE;\ mtc0 k0, MIPS_COP_0_STATUS /* * The kernel exception stack contains 18 saved general registers, * the status register and the multiply lo and high registers. * In addition, we set this up for linkage conventions. */ #define KERN_REG_SIZE (NUMSAVEREGS * SZREG) #define KERN_EXC_FRAME_SIZE (CALLFRAME_SIZ + KERN_REG_SIZE + 16) NESTED_NOPROFILE(MipsKernGenException, KERN_EXC_FRAME_SIZE, ra) .set noat PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE) /* * Save CPU state, building 'frame'. */ SAVE_CPU /* * Call the exception handler. a0 points at the saved frame. */ PTR_LA gp, _C_LABEL(_gp) PTR_LA k0, _C_LABEL(trap) jalr k0 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging /* * Update interrupt and CPU mask in saved status register * Some of interrupts could be disabled by * intr filters if interrupts are enabled later * in trap handler */ mfc0 a0, MIPS_COP_0_STATUS and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) RESTORE_REG(a1, SR, sp) and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) or a1, a1, a0 SAVE_REG(a1, SR, sp) RESTORE_CPU # v0 contains the return address. sync eret .set at END(MipsKernGenException) /*---------------------------------------------------------------------------- * * MipsUserGenException -- * * Handle an exception from user mode. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ NESTED_NOPROFILE(MipsUserGenException, CALLFRAME_SIZ, ra) .set noat .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) /* * Save all of the registers except for the kernel temporaries in u.u_pcb. */ GET_CPU_PCPU(k1) PTR_L k1, PC_CURPCB(k1) SAVE_U_PCB_REG(AT, AST, k1) .set at SAVE_U_PCB_REG(v0, V0, k1) SAVE_U_PCB_REG(v1, V1, k1) SAVE_U_PCB_REG(a0, A0, k1) mflo v0 SAVE_U_PCB_REG(a1, A1, k1) SAVE_U_PCB_REG(a2, A2, k1) SAVE_U_PCB_REG(a3, A3, k1) SAVE_U_PCB_REG(t0, T0, k1) mfhi v1 SAVE_U_PCB_REG(t1, T1, k1) SAVE_U_PCB_REG(t2, T2, k1) SAVE_U_PCB_REG(t3, T3, k1) SAVE_U_PCB_REG(ta0, TA0, k1) mfc0 a0, MIPS_COP_0_STATUS # First arg is the status reg. SAVE_U_PCB_REG(ta1, TA1, k1) SAVE_U_PCB_REG(ta2, TA2, k1) SAVE_U_PCB_REG(ta3, TA3, k1) SAVE_U_PCB_REG(s0, S0, k1) mfc0 a1, MIPS_COP_0_CAUSE # Second arg is the cause reg. SAVE_U_PCB_REG(s1, S1, k1) SAVE_U_PCB_REG(s2, S2, k1) SAVE_U_PCB_REG(s3, S3, k1) SAVE_U_PCB_REG(s4, S4, k1) MFC0 a2, MIPS_COP_0_BAD_VADDR # Third arg is the fault addr SAVE_U_PCB_REG(s5, S5, k1) SAVE_U_PCB_REG(s6, S6, k1) SAVE_U_PCB_REG(s7, S7, k1) SAVE_U_PCB_REG(t8, T8, k1) MFC0 a3, MIPS_COP_0_EXC_PC # Fourth arg is the pc. SAVE_U_PCB_REG(t9, T9, k1) SAVE_U_PCB_REG(gp, GP, k1) SAVE_U_PCB_REG(sp, SP, k1) SAVE_U_PCB_REG(s8, S8, k1) PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP SAVE_U_PCB_REG(ra, RA, k1) SAVE_U_PCB_REG(v0, MULLO, k1) SAVE_U_PCB_REG(v1, MULHI, k1) SAVE_U_PCB_REG(a0, SR, k1) SAVE_U_PCB_REG(a1, CAUSE, k1) SAVE_U_PCB_REG(a2, BADVADDR, k1) SAVE_U_PCB_REG(a3, PC, k1) REG_S a3, CALLFRAME_RA(sp) # for debugging PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP # Turn off fpu and enter kernel mode and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_KSU_MASK | MIPS_SR_INT_IE) #if defined(CPU_CNMIPS) and t0, t0, ~(MIPS_SR_COP_2_BIT) or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) #elif defined(CPU_RMI) || defined(CPU_NLM) or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) #endif mtc0 t0, MIPS_COP_0_STATUS PTR_ADDU a0, k1, U_PCB_REGS ITLBNOPFIX /* * Call the exception handler. */ PTR_LA k0, _C_LABEL(trap) jalr k0 nop /* * Restore user registers and return. * First disable interrupts and set exeption level. */ DO_AST CLEAR_STATUS /* * The use of k1 for storing the PCB pointer must be done only * after interrupts are disabled. Otherwise it will get overwritten * by the interrupt code. */ GET_CPU_PCPU(k1) PTR_L k1, PC_CURPCB(k1) /* * Update interrupt mask in saved status register * Some of interrupts could be enabled by ithread * scheduled by ast() */ mfc0 a0, MIPS_COP_0_STATUS and a0, a0, MIPS_SR_INT_MASK RESTORE_U_PCB_REG(a1, SR, k1) and a1, a1, ~MIPS_SR_INT_MASK or a1, a1, a0 SAVE_U_PCB_REG(a1, SR, k1) RESTORE_U_PCB_REG(t0, MULLO, k1) RESTORE_U_PCB_REG(t1, MULHI, k1) mtlo t0 mthi t1 RESTORE_U_PCB_REG(a0, PC, k1) RESTORE_U_PCB_REG(v0, V0, k1) MTC0 a0, MIPS_COP_0_EXC_PC # set return address RESTORE_U_PCB_REG(v1, V1, k1) RESTORE_U_PCB_REG(a0, A0, k1) RESTORE_U_PCB_REG(a1, A1, k1) RESTORE_U_PCB_REG(a2, A2, k1) RESTORE_U_PCB_REG(a3, A3, k1) RESTORE_U_PCB_REG(t0, T0, k1) RESTORE_U_PCB_REG(t1, T1, k1) RESTORE_U_PCB_REG(t2, T2, k1) RESTORE_U_PCB_REG(t3, T3, k1) RESTORE_U_PCB_REG(ta0, TA0, k1) RESTORE_U_PCB_REG(ta1, TA1, k1) RESTORE_U_PCB_REG(ta2, TA2, k1) RESTORE_U_PCB_REG(ta3, TA3, k1) RESTORE_U_PCB_REG(s0, S0, k1) RESTORE_U_PCB_REG(s1, S1, k1) RESTORE_U_PCB_REG(s2, S2, k1) RESTORE_U_PCB_REG(s3, S3, k1) RESTORE_U_PCB_REG(s4, S4, k1) RESTORE_U_PCB_REG(s5, S5, k1) RESTORE_U_PCB_REG(s6, S6, k1) RESTORE_U_PCB_REG(s7, S7, k1) RESTORE_U_PCB_REG(t8, T8, k1) RESTORE_U_PCB_REG(t9, T9, k1) RESTORE_U_PCB_REG(gp, GP, k1) RESTORE_U_PCB_REG(sp, SP, k1) RESTORE_U_PCB_REG(k0, SR, k1) RESTORE_U_PCB_REG(s8, S8, k1) RESTORE_U_PCB_REG(ra, RA, k1) .set noat RESTORE_U_PCB_REG(AT, AST, k1) mtc0 k0, MIPS_COP_0_STATUS # still exception level ITLBNOPFIX sync eret .set at END(MipsUserGenException) .set push .set noat NESTED(mips_wait, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) REG_S ra, CALLFRAME_RA(sp) # save RA mfc0 t0, MIPS_COP_0_STATUS xori t1, t0, MIPS_SR_INT_IE mtc0 t1, MIPS_COP_0_STATUS COP0_SYNC jal sched_runnable nop REG_L ra, CALLFRAME_RA(sp) mfc0 t0, MIPS_COP_0_STATUS ori t1, t0, MIPS_SR_INT_IE .align 4 GLOBAL(MipsWaitStart) # this is 16 byte aligned mtc0 t1, MIPS_COP_0_STATUS bnez v0, MipsWaitEnd nop +#if defined(CPU_XBURST) && defined(SMP) + nop +#else wait +#endif GLOBAL(MipsWaitEnd) # MipsWaitStart + 16 jr ra PTR_ADDU sp, sp, CALLFRAME_SIZ END(mips_wait) .set pop /*---------------------------------------------------------------------------- * * MipsKernIntr -- * * Handle an interrupt from kernel mode. * Interrupts use the standard kernel stack. * switch_exit sets up a kernel stack after exit so interrupts won't fail. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ NESTED_NOPROFILE(MipsKernIntr, KERN_EXC_FRAME_SIZE, ra) .set noat PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE .mask 0x80000000, (CALLFRAME_RA - KERN_EXC_FRAME_SIZE) /* * Check for getting interrupts just before wait */ MFC0 k0, MIPS_COP_0_EXC_PC ori k0, 0xf xori k0, 0xf # 16 byte align PTR_LA k1, MipsWaitStart bne k0, k1, 1f nop PTR_ADDU k1, 16 # skip over wait MTC0 k1, MIPS_COP_0_EXC_PC 1: /* * Save CPU state, building 'frame'. */ SAVE_CPU /* * Call the interrupt handler. a0 points at the saved frame. */ PTR_LA gp, _C_LABEL(_gp) #ifdef INTRNG PTR_LA k0, _C_LABEL(intr_irq_handler) #else PTR_LA k0, _C_LABEL(cpu_intr) #endif jalr k0 REG_S a3, CALLFRAME_RA + KERN_REG_SIZE(sp) # for debugging /* * Update interrupt and CPU mask in saved status register * Some of interrupts could be disabled by * intr filters if interrupts are enabled later * in trap handler */ mfc0 a0, MIPS_COP_0_STATUS and a0, a0, (MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) RESTORE_REG(a1, SR, sp) and a1, a1, ~(MIPS_SR_INT_MASK|MIPS_SR_COP_USABILITY) or a1, a1, a0 SAVE_REG(a1, SR, sp) REG_L v0, CALLFRAME_RA + KERN_REG_SIZE(sp) RESTORE_CPU # v0 contains the return address. sync eret .set at END(MipsKernIntr) /*---------------------------------------------------------------------------- * * MipsUserIntr -- * * Handle an interrupt from user mode. * Note: we save minimal state in the u.u_pcb struct and use the standard * kernel stack since there has to be a u page if we came from user mode. * If there is a pending software interrupt, then save the remaining state * and call softintr(). This is all because if we call switch() inside * interrupt(), not all the user registers have been saved in u.u_pcb. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ NESTED_NOPROFILE(MipsUserIntr, CALLFRAME_SIZ, ra) .set noat .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) /* * Save the relevant user registers into the u.u_pcb struct. * We don't need to save s0 - s8 because the compiler does it for us. */ GET_CPU_PCPU(k1) PTR_L k1, PC_CURPCB(k1) SAVE_U_PCB_REG(AT, AST, k1) .set at SAVE_U_PCB_REG(v0, V0, k1) SAVE_U_PCB_REG(v1, V1, k1) SAVE_U_PCB_REG(a0, A0, k1) SAVE_U_PCB_REG(a1, A1, k1) SAVE_U_PCB_REG(a2, A2, k1) SAVE_U_PCB_REG(a3, A3, k1) SAVE_U_PCB_REG(t0, T0, k1) SAVE_U_PCB_REG(t1, T1, k1) SAVE_U_PCB_REG(t2, T2, k1) SAVE_U_PCB_REG(t3, T3, k1) SAVE_U_PCB_REG(ta0, TA0, k1) SAVE_U_PCB_REG(ta1, TA1, k1) SAVE_U_PCB_REG(ta2, TA2, k1) SAVE_U_PCB_REG(ta3, TA3, k1) SAVE_U_PCB_REG(t8, T8, k1) SAVE_U_PCB_REG(t9, T9, k1) SAVE_U_PCB_REG(gp, GP, k1) SAVE_U_PCB_REG(sp, SP, k1) SAVE_U_PCB_REG(ra, RA, k1) /* * save remaining user state in u.u_pcb. */ SAVE_U_PCB_REG(s0, S0, k1) SAVE_U_PCB_REG(s1, S1, k1) SAVE_U_PCB_REG(s2, S2, k1) SAVE_U_PCB_REG(s3, S3, k1) SAVE_U_PCB_REG(s4, S4, k1) SAVE_U_PCB_REG(s5, S5, k1) SAVE_U_PCB_REG(s6, S6, k1) SAVE_U_PCB_REG(s7, S7, k1) SAVE_U_PCB_REG(s8, S8, k1) mflo v0 # get lo/hi late to avoid stall mfhi v1 mfc0 a0, MIPS_COP_0_STATUS mfc0 a1, MIPS_COP_0_CAUSE MFC0 a3, MIPS_COP_0_EXC_PC SAVE_U_PCB_REG(v0, MULLO, k1) SAVE_U_PCB_REG(v1, MULHI, k1) SAVE_U_PCB_REG(a0, SR, k1) SAVE_U_PCB_REG(a1, CAUSE, k1) SAVE_U_PCB_REG(a3, PC, k1) # PC in a3, note used later! PTR_SUBU sp, k1, CALLFRAME_SIZ # switch to kernel SP PTR_LA gp, _C_LABEL(_gp) # switch to kernel GP # Turn off fpu, disable interrupts, set kernel mode kernel mode, clear exception level. and t0, a0, ~(MIPS_SR_COP_1_BIT | MIPS_SR_EXL | MIPS_SR_INT_IE | MIPS_SR_KSU_MASK) #ifdef CPU_CNMIPS and t0, t0, ~(MIPS_SR_COP_2_BIT) or t0, t0, (MIPS_SR_KX | MIPS_SR_SX | MIPS_SR_UX | MIPS_SR_PX) #elif defined(CPU_RMI) || defined(CPU_NLM) or t0, t0, (MIPS_SR_KX | MIPS_SR_UX | MIPS_SR_COP_2_BIT) #endif mtc0 t0, MIPS_COP_0_STATUS ITLBNOPFIX PTR_ADDU a0, k1, U_PCB_REGS /* * Call the interrupt handler. */ #ifdef INTRNG PTR_LA k0, _C_LABEL(intr_irq_handler) #else PTR_LA k0, _C_LABEL(cpu_intr) #endif jalr k0 REG_S a3, CALLFRAME_RA(sp) # for debugging /* * Enable interrupts before doing ast(). * * On SMP kernels the AST processing might trigger IPI to other processors. * If that processor is also doing AST processing with interrupts disabled * then we may deadlock. */ mfc0 a0, MIPS_COP_0_STATUS or a0, a0, MIPS_SR_INT_IE mtc0 a0, MIPS_COP_0_STATUS ITLBNOPFIX /* * DO_AST enabled interrupts */ DO_AST /* * Restore user registers and return. */ CLEAR_STATUS GET_CPU_PCPU(k1) PTR_L k1, PC_CURPCB(k1) /* * Update interrupt mask in saved status register * Some of interrupts could be disabled by * intr filters */ mfc0 a0, MIPS_COP_0_STATUS and a0, a0, MIPS_SR_INT_MASK RESTORE_U_PCB_REG(a1, SR, k1) and a1, a1, ~MIPS_SR_INT_MASK or a1, a1, a0 SAVE_U_PCB_REG(a1, SR, k1) RESTORE_U_PCB_REG(s0, S0, k1) RESTORE_U_PCB_REG(s1, S1, k1) RESTORE_U_PCB_REG(s2, S2, k1) RESTORE_U_PCB_REG(s3, S3, k1) RESTORE_U_PCB_REG(s4, S4, k1) RESTORE_U_PCB_REG(s5, S5, k1) RESTORE_U_PCB_REG(s6, S6, k1) RESTORE_U_PCB_REG(s7, S7, k1) RESTORE_U_PCB_REG(s8, S8, k1) RESTORE_U_PCB_REG(t0, MULLO, k1) RESTORE_U_PCB_REG(t1, MULHI, k1) RESTORE_U_PCB_REG(t2, PC, k1) mtlo t0 mthi t1 MTC0 t2, MIPS_COP_0_EXC_PC # set return address RESTORE_U_PCB_REG(v0, V0, k1) RESTORE_U_PCB_REG(v1, V1, k1) RESTORE_U_PCB_REG(a0, A0, k1) RESTORE_U_PCB_REG(a1, A1, k1) RESTORE_U_PCB_REG(a2, A2, k1) RESTORE_U_PCB_REG(a3, A3, k1) RESTORE_U_PCB_REG(t0, T0, k1) RESTORE_U_PCB_REG(t1, T1, k1) RESTORE_U_PCB_REG(t2, T2, k1) RESTORE_U_PCB_REG(t3, T3, k1) RESTORE_U_PCB_REG(ta0, TA0, k1) RESTORE_U_PCB_REG(ta1, TA1, k1) RESTORE_U_PCB_REG(ta2, TA2, k1) RESTORE_U_PCB_REG(ta3, TA3, k1) RESTORE_U_PCB_REG(t8, T8, k1) RESTORE_U_PCB_REG(t9, T9, k1) RESTORE_U_PCB_REG(gp, GP, k1) RESTORE_U_PCB_REG(k0, SR, k1) RESTORE_U_PCB_REG(sp, SP, k1) RESTORE_U_PCB_REG(ra, RA, k1) .set noat RESTORE_U_PCB_REG(AT, AST, k1) mtc0 k0, MIPS_COP_0_STATUS # SR with EXL set. ITLBNOPFIX sync eret .set at END(MipsUserIntr) LEAF_NOPROFILE(MipsTLBInvalidException) .set push .set noat .set noreorder MFC0 k0, MIPS_COP_0_BAD_VADDR PTR_LI k1, VM_MAXUSER_ADDRESS sltu k1, k0, k1 bnez k1, 1f nop /* Kernel address. */ lui k1, %hi(kernel_segmap) # k1=hi of segbase b 2f PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base 1: /* User address. */ GET_CPU_PCPU(k1) PTR_L k1, PC_SEGBASE(k1) 2: /* Validate page directory pointer. */ beqz k1, 3f nop PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost) beq k1, zero, MipsKernGenException # ==0 -- no seg tab andi k0, k0, PDEPTRMASK #06: k0=seg offset PTR_ADDU k1, k0, k1 # k1=seg entry address PTR_L k1, 0(k1) # k1=seg entry /* Validate page table pointer. */ beqz k1, 3f nop #ifdef __mips_n64 MFC0 k0, MIPS_COP_0_BAD_VADDR PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=pde offset (almost) beq k1, zero, MipsKernGenException # ==0 -- no pde tab andi k0, k0, PDEPTRMASK # k0=pde offset PTR_ADDU k1, k0, k1 # k1=pde entry address PTR_L k1, 0(k1) # k1=pde entry /* Validate pde table pointer. */ beqz k1, 3f nop #endif MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN andi k0, k0, PTEMASK # k0=page tab offset PTR_ADDU k1, k1, k0 # k1=pte address PTE_L k0, 0(k1) # k0=this PTE /* Validate page table entry. */ andi k0, PTE_V beqz k0, 3f nop /* Check whether this is an even or odd entry. */ andi k0, k1, PTESIZE bnez k0, odd_page nop PTE_L k0, 0(k1) PTE_L k1, PTESIZE(k1) CLEAR_PTE_SWBITS(k0) PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 COP0_SYNC CLEAR_PTE_SWBITS(k1) PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 COP0_SYNC b tlb_insert_entry nop odd_page: PTE_L k0, -PTESIZE(k1) PTE_L k1, 0(k1) CLEAR_PTE_SWBITS(k0) PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 COP0_SYNC CLEAR_PTE_SWBITS(k1) PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 COP0_SYNC tlb_insert_entry: tlbp HAZARD_DELAY mfc0 k0, MIPS_COP_0_TLB_INDEX bltz k0, tlb_insert_random nop tlbwi eret ssnop tlb_insert_random: tlbwr eret ssnop 3: /* * Branch to the comprehensive exception processing. */ mfc0 k1, MIPS_COP_0_STATUS andi k1, k1, MIPS_SR_KSU_USER bnez k1, _C_LABEL(MipsUserGenException) nop /* * Check for kernel stack overflow. */ GET_CPU_PCPU(k1) PTR_L k0, PC_CURTHREAD(k1) PTR_L k0, TD_KSTACK(k0) sltu k0, k0, sp bnez k0, _C_LABEL(MipsKernGenException) nop /* * Kernel stack overflow. * * Move to a valid stack before we call panic. We use the boot stack * for this purpose. */ GET_CPU_PCPU(k1) lw k1, PC_CPUID(k1) sll k1, k1, PAGE_SHIFT + 1 PTR_LA k0, _C_LABEL(pcpu_space) PTR_ADDU k0, PAGE_SIZE * 2 PTR_ADDU k0, k0, k1 /* * Stash the original value of 'sp' so we can update trapframe later. * We assume that SAVE_CPU does not trash 'k1'. */ move k1, sp move sp, k0 PTR_SUBU sp, sp, KERN_EXC_FRAME_SIZE move k0, ra move ra, zero REG_S ra, CALLFRAME_RA(sp) /* stop the ddb backtrace right here */ REG_S zero, CALLFRAME_SP(sp) move ra, k0 SAVE_CPU /* * Now restore the value of 'sp' at the time of the tlb exception in * the trapframe. */ SAVE_REG(k1, SP, sp) /* * Squelch any more overflow checks by setting the stack base to 0. */ GET_CPU_PCPU(k1) PTR_L k0, PC_CURTHREAD(k1) PTR_S zero, TD_KSTACK(k0) move a1, a0 PANIC("kernel stack overflow - trapframe at %p") /* * This nop is necessary so that the 'ra' remains within the bounds * of this handler. Otherwise the ddb backtrace code will think that * the panic() was called from MipsTLBMissException. */ nop .set pop END(MipsTLBInvalidException) /*---------------------------------------------------------------------------- * * MipsTLBMissException -- * * Handle a TLB miss exception from kernel mode in kernel space. * The BaddVAddr, Context, and EntryHi registers contain the failed * virtual address. * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ LEAF_NOPROFILE(MipsTLBMissException) .set noat MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address PTR_LI k1, VM_MAX_KERNEL_ADDRESS # check fault address against sltu k1, k1, k0 # upper bound of kernel_segmap bnez k1, MipsKernGenException # out of bound lui k1, %hi(kernel_segmap) # k1=hi of segbase PTR_SRL k0, SEGSHIFT - PTRSHIFT # k0=seg offset (almost) PTR_L k1, %lo(kernel_segmap)(k1) # k1=segment tab base beq k1, zero, MipsKernGenException # ==0 -- no seg tab andi k0, k0, PDEPTRMASK #06: k0=seg offset PTR_ADDU k1, k0, k1 # k1=seg entry address PTR_L k1, 0(k1) # k1=seg entry MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) beq k1, zero, MipsKernGenException # ==0 -- no page table #ifdef __mips_n64 PTR_SRL k0, PDRSHIFT - PTRSHIFT # k0=VPN andi k0, k0, PDEPTRMASK # k0=pde offset PTR_ADDU k1, k0, k1 # k1=pde entry address PTR_L k1, 0(k1) # k1=pde entry MFC0 k0, MIPS_COP_0_BAD_VADDR # k0=bad address (again) beq k1, zero, MipsKernGenException # ==0 -- no page table #endif PTR_SRL k0, PAGE_SHIFT - PTESHIFT # k0=VPN andi k0, k0, PTE2MASK # k0=page tab offset PTR_ADDU k1, k1, k0 # k1=pte address PTE_L k0, 0(k1) # k0=lo0 pte PTE_L k1, PTESIZE(k1) # k1=lo1 pte CLEAR_PTE_SWBITS(k0) PTE_MTC0 k0, MIPS_COP_0_TLB_LO0 # lo0 is loaded COP0_SYNC CLEAR_PTE_SWBITS(k1) PTE_MTC0 k1, MIPS_COP_0_TLB_LO1 # lo1 is loaded COP0_SYNC tlbwr # write to tlb HAZARD_DELAY eret # return from exception .set at END(MipsTLBMissException) /*---------------------------------------------------------------------------- * * MipsFPTrap -- * * Handle a floating point Trap. * * MipsFPTrap(statusReg, causeReg, pc) * unsigned statusReg; * unsigned causeReg; * unsigned pc; * * Results: * None. * * Side effects: * None. * *---------------------------------------------------------------------------- */ NESTED(MipsFPTrap, CALLFRAME_SIZ, ra) PTR_SUBU sp, sp, CALLFRAME_SIZ mfc0 t0, MIPS_COP_0_STATUS HAZARD_DELAY REG_S ra, CALLFRAME_RA(sp) .mask 0x80000000, (CALLFRAME_RA - CALLFRAME_SIZ) #if defined(__mips_n64) or t1, t0, MIPS_SR_COP_1_BIT | MIPS_SR_FR #else or t1, t0, MIPS_SR_COP_1_BIT #endif mtc0 t1, MIPS_COP_0_STATUS HAZARD_DELAY ITLBNOPFIX cfc1 t1, MIPS_FPU_CSR # stall til FP done cfc1 t1, MIPS_FPU_CSR # now get status nop sll t2, t1, (31 - 17) # unimplemented operation? bgez t2, 3f # no, normal trap nop /* * We got an unimplemented operation trap so * fetch the instruction, compute the next PC and emulate the instruction. */ bgez a1, 1f # Check the branch delay bit. nop /* * The instruction is in the branch delay slot so the branch will have to * be emulated to get the resulting PC. */ PTR_S a2, CALLFRAME_SIZ + 8(sp) GET_CPU_PCPU(a0) #mips64 unsafe? PTR_L a0, PC_CURPCB(a0) PTR_ADDU a0, a0, U_PCB_REGS # first arg is ptr to CPU registers move a1, a2 # second arg is instruction PC move a2, t1 # third arg is floating point CSR PTR_LA t3, _C_LABEL(MipsEmulateBranch) # compute PC after branch jalr t3 # compute PC after branch move a3, zero # fourth arg is FALSE /* * Now load the floating-point instruction in the branch delay slot * to be emulated. */ PTR_L a2, CALLFRAME_SIZ + 8(sp) # restore EXC pc b 2f lw a0, 4(a2) # a0 = coproc instruction /* * This is not in the branch delay slot so calculate the resulting * PC (epc + 4) into v0 and continue to MipsEmulateFP(). */ 1: lw a0, 0(a2) # a0 = coproc instruction #xxx mips64 unsafe? PTR_ADDU v0, a2, 4 # v0 = next pc 2: GET_CPU_PCPU(t2) PTR_L t2, PC_CURPCB(t2) SAVE_U_PCB_REG(v0, PC, t2) # save new pc /* * Check to see if the instruction to be emulated is a floating-point * instruction. */ srl a3, a0, MIPS_OPCODE_SHIFT beq a3, MIPS_OPCODE_C1, 4f # this should never fail nop /* * Send a floating point exception signal to the current process. */ 3: GET_CPU_PCPU(a0) PTR_L a0, PC_CURTHREAD(a0) # get current thread cfc1 a2, MIPS_FPU_CSR # code = FP execptions ctc1 zero, MIPS_FPU_CSR # Clear exceptions PTR_LA t3, _C_LABEL(trapsignal) jalr t3 li a1, SIGFPE b FPReturn nop /* * Finally, we can call MipsEmulateFP() where a0 is the instruction to emulate. */ 4: PTR_LA t3, _C_LABEL(MipsEmulateFP) jalr t3 nop /* * Turn off the floating point coprocessor and return. */ FPReturn: mfc0 t0, MIPS_COP_0_STATUS PTR_L ra, CALLFRAME_RA(sp) and t0, t0, ~MIPS_SR_COP_1_BIT mtc0 t0, MIPS_COP_0_STATUS ITLBNOPFIX j ra PTR_ADDU sp, sp, CALLFRAME_SIZ END(MipsFPTrap) #ifndef INTRNG /* * Interrupt counters for vmstat. */ .data .globl intrcnt .globl sintrcnt .globl intrnames .globl sintrnames intrnames: .space INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 sintrnames: #ifdef __mips_n64 .quad INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 #else .int INTRCNT_COUNT * (MAXCOMLEN + 1) * 2 #endif .align (_MIPS_SZLONG / 8) intrcnt: .space INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 sintrcnt: #ifdef __mips_n64 .quad INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 #else .int INTRCNT_COUNT * (_MIPS_SZLONG / 8) * 2 #endif #endif /* INTRNG */ /* * Vector to real handler in KSEG1. */ .text VECTOR(MipsCache, unknown) PTR_LA k0, _C_LABEL(MipsCacheException) li k1, MIPS_KSEG0_PHYS_MASK and k0, k1 PTR_LI k1, MIPS_KSEG1_START or k0, k1 j k0 nop VECTOR_END(MipsCache) .set at /* * Panic on cache errors. A lot more could be done to recover * from some types of errors but it is tricky. */ NESTED_NOPROFILE(MipsCacheException, KERN_EXC_FRAME_SIZE, ra) .set noat .mask 0x80000000, -4 PTR_LA k0, _C_LABEL(panic) # return to panic PTR_LA a0, 9f # panicstr MFC0 a1, MIPS_COP_0_ERROR_PC mfc0 a2, MIPS_COP_0_CACHE_ERR # 3rd arg cache error MTC0 k0, MIPS_COP_0_ERROR_PC # set return address mfc0 k0, MIPS_COP_0_STATUS # restore status li k1, MIPS_SR_DIAG_PE # ignore further errors or k0, k1 mtc0 k0, MIPS_COP_0_STATUS # restore status COP0_SYNC eret MSG("cache error @ EPC 0x%x CachErr 0x%x"); .set at END(MipsCacheException) Index: projects/clang390-import =================================================================== --- projects/clang390-import (revision 308867) +++ projects/clang390-import (revision 308868) Property changes on: projects/clang390-import ___________________________________________________________________ Modified: svn:mergeinfo ## -0,0 +0,1 ## Merged /head:r308842-308867